I have two threads and I need to run a task from the first thread but in such a way that the task is executed in the second thread.
For this I decided to use boost::asio::post, but I'm not sure if it is correct (and thread safe).
Is it correct to call boost::asio::post on an io_context that is running in another thread?
In other words, is the following code correct?
#include <boost/asio.hpp>
#include <iostream>
#include <thread>
#include <chrono>
void my_task() {
std::cout << "Task is running in thread: " << std::this_thread::get_id() << std::endl;
}
int main() {
boost::asio::io_context io;
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> work_guard =
boost::asio::make_work_guard(io);
std::thread io_thread([&io]() {
std::cout << "io_context is running in thread: " << std::this_thread::get_id() << std::endl;
io.run();
std::cout << "io_context stopped." << std::endl;
});
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "Posting task from main thread: " << std::this_thread::get_id() << std::endl;
boost::asio::post(io, &my_task);
std::this_thread::sleep_for(std::chrono::milliseconds(200));
work_guard.reset();
io_thread.join();
}
Yes. io_context is thread-safe:
Distinct objects: Safe.
Shared objects: Safe, with the specific exceptions of the restart() and notify_fork() functions. Calling restart() while there are unfinished run(), run_one(), run_for(), run_until(), poll() or poll_one() calls results in undefined behaviour. The notify_fork() function should not be called while any io_context function, or any function on an I/O object that is associated with the io_context, is being called in another thread.
This includes the use of (copies of) the executor. It's explicitly what executors are designed for.
Post ends up calling execute() on an executor and the Executor Requirements state:
None of an executor type's copy constructor, destructor, equality comparison, swap function, execute function, or associated query functions shall introduce data races as a result of concurrent invocations of those functions from different threads.
Only limitation is that the executor(s) cannot be used after the end of the context's lifetime.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With