how in BOOST send a signal in a thread and have the corresponding slot executed in another thread?
For an event loop use boost::asio::io_service. You can post tasks inside this object and have another thread execute them, in a thread safe way:
struct MyClass
{
boost::io_service service;
void doSomethingOp() const { ... }
void doSomething()
{
service.post(boost::bind(&MyClass::doSomethingOp, this));
}
void loop()
{
service.run(); // processes the tasks
}
};
boost::signal<void()> mySignal;
MyClass myClass;
mySignal.connect(boost::bind(&MyClass::doSomething, boost::ref(myClass)));
// launches a thread and executes myClass.loop() there
boost::thread t(boost::bind(&MyClass::loop(), boost::ref(myClass)));
// calls myClass.doSomething() in this thread, but loop() executes it in the other
mySignal();
Not directly, because boost does not provide an event loop.
To have a signal handled in another thread, that another thread needs to be checking the queue of handlers it should run and execute them (which usually means some kind of event-loop). Boost does not provide one, so you'll need to get it from elsewhere or write it.
If you have an event-loop, that does not provide signals, (or implement some simple solution with queues) you should be able to (ab)use boost.signals2 (not boost.signals, because that version is not thread-safe) by overriding the operator+=
to wrap each handler in something, that will queue it for execution in the other thread. You might even be able to implement it for signals with return values (which is not supported by Qt, but is supported by boost), but you'll have to be careful to avoid dead-lock.
Here's a complete example of the above mentioned io_service
, executor_work_guard
, signals2::signal
.
io_service
is the event loop handlerexecutor_work_guard
make sure the m_service.run() doesn't only execute oncesignal
/slot
decouples the sender and receiver- the
thread
runs all the process of theio_service
#include <boost/thread.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/executor_work_guard.hpp>
#include <boost/signals2/signal.hpp>
class IOService
{
public:
IOService() : m_worker(boost::asio::make_work_guard(m_service)) {}
~IOService() {}
// slot to receive signal
void slotMessage(std::string msg)
{
m_service.post(boost::bind(&IOService::process, this, msg));
}
// start/close background thread
bool start()
{
if (m_started)
return true;
m_started = true;
// start reader thread
m_thread = boost::thread(boost::bind(&IOService::loop, this));
return m_started;
}
void loop()
{
m_service.run();
}
void close()
{
m_worker.reset();
if (m_thread.joinable())
m_thread.join();
m_started = false;
}
// process
void process(std::string msg)
{
printf("process %s\n", msg.c_str());
}
private:
bool m_started = false;
boost::asio::io_service m_service;
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> m_worker;
boost::thread m_thread;
};
int main()
{
// service instance
IOService serv;
serv.start();
// signal to slot
boost::signals2::signal<void(std::string)> signalMessage;
signalMessage.connect(boost::bind(&IOService::slotMessage, boost::ref(serv), _1));
// send one signal
signalMessage("abc");
// wait and quit
boost::this_thread::sleep(boost::chrono::seconds(2));
serv.close();
}