Reputation: 6162
How can one call a boost signals2 slot on a separate thread without blocking the thread that is emitting the signal? I would like to get the functionality of the Qt5 QObject::connect
with the QueuedConnection argument; for Qt5 details see Threads and QObjects. That is, I need to be able to emit a boost signals2 signal with no possiblity of blocking the thread that is emitting the signal; the slots that are connected are called from a separate "event" thread.
I like the functionality of the Qt5 API, but I cannot have QObject as a base class and the additional MOC machinery in my API and implementation. Boost signals2 is thread safe in its connection handling, but it is not multithreaded (really I am just looking for non-blocking) in its calls to connected slots.
I believe a combination of boost signals2 and asio as an event loop could do what I need, but I am unsure how to implement this. Plus, I am sure other people have had similar needs, so I am looking for ideas and suggestions on how to achieve this.
Thanks!
Upvotes: 2
Views: 1553
Reputation: 4575
boost::signals2::signal
invoke slots sequentially on the thread that emits the signal. If you wish to achieve a non blocking behavior you would simply have to emit the signal on a different thread yourself.
From what I understand, Qt QueuedConnection not only means the slot is invoked asynchronously, but on the receiver specific thread event loop. This is different from invoking the slot on a arbitrary thread. Your intent is not 100% clear to me.
Assuming you don't care on which thread the slot is invoked, so long as it does not block, you could wrap your signal in a small object that posts to a different thread.
A simple example, using boost::asio
:
struct async_signal : std::enable_shared_from_this<async_signal>
{
boost::signals2::signal<void(void)> signal;
boost::asio::io_context executor;
void emit_async()
{
boost::asio::post(excutor, [self_weak = weak_from_this()]()
{
if (auto self = self_weak.lock())
{
signal();
}
});
}
}
Now the slots will be invoked sequentially on whichever thread(s) that call io_context::run(). This is usually a thread pool of some sort such as boost::asio::thread_pool
;
If you are wondering about the std::enable_shared_from_this
part, this is for thread safety.
You could of course make this class templated and well encapsulated, but I think its easier to understand this way.
Upvotes: 4