boost signal and slot not working in different thread (using boost::asio::io_service)

692 Views Asked by At

I have written a small test program to understand the signal and slot mechanism provided by boost and their behavior when posted in different thread. I want to have slot's being called in different threads but the output of my program shows slots are not being called in different thread from which signal was emitted.

#include <iostream>

#include <boost/thread.hpp>
#include <boost/chrono.hpp>
#include <boost/random.hpp>
#include <boost/signals2.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/signals2/signal.hpp>


boost::signals2::signal<void (int)> randomNumberSig;


// ---------------- Thread 1 ----------------

boost::asio::io_service thread1_serv;

void handle_rnd_1(int number)
{
    std::cout << "Thread1: " << boost::this_thread::get_id() << " & Number is " << number << std::endl;
}

void thread1_init(void)
{
    std::cout << "Thread 1 Init" << std::endl;
    boost::asio::io_service::work work (thread1_serv); 
    randomNumberSig.connect([] (int num) -> void {
        std::cout << "Slot called from main thread" << std::endl;
        thread1_serv.post(boost::bind(handle_rnd_1, num));
    });
}

void thread1_loop(void)
{

}

void thread1(void)
{
    thread1_init();
    while (true) {
        thread1_serv.run();
        thread1_loop();
    }
}

int main(int argc, char *argv[])
{
    std::cout << "Starting the Program" << std::endl;
    boost::thread t1(&thread1);

    while (1) {
        int num = 2;

        std::cout << "Thread " << boost::this_thread::get_id() << " & Number: " << num << std::endl;
        randomNumberSig(num);
        boost::this_thread::sleep_for(boost::chrono::seconds(num));
    }
    return 0;
}

The output of the program is:

Starting the Program
Thread 7fae3a2ba3c0 & Number: 2
Thread 1 Init
Thread 7fae3a2ba3c0 & Number: 2
Slot called from main thread
Thread 7fae3a2ba3c0 & Number: 2
Slot called from main thread
Thread 7fae3a2ba3c0 & Number: 2
Slot called from main thread

I suspect post() method of the io_service is not working properly or I have missed something in initializing the io_service.

1

There are 1 best solutions below

2
rafix07 On BEST ANSWER

You don't handle invocation of run function properly.

You used work to prevent run from ending when there is no work to do. But your work is local inside thread1_init so when this function ends, work is destroyed and io_service::run exits when there are no handlers to be called. After run finished, io_service is marked as stopped, and you need to call restart before calling run (as subsequent invocation). If you don't call restart, run returns immediately without processing any handlers - that is why you don't see them.

So first solution is to create work whose lifetime is the same as io_service (just use global variable - ugly):

boost::asio::io_service thread1_serv;
boost::asio::io_service::work work(thread1_serv);

Another solution, don't use work, just call restart before run:

thread1_init();
while (true) {
    thread1_serv.restart();
    thread1_serv.run();
    thread1_loop();
}

Wandbox test