Reputation: 7368
I need to post a lamda to an io_context
but I want to have the guarantee that the handler is executed only after the post()
call. Following a simplified snippet:
auto l = [] { cout << "hello lambda"; };
int f(asio::io_context& io) {
io.post(l);
}
int main() {
asio::io_context io;
thread th{[&io] { io.run(); };
f(io);
cout << "hello main";
th.join();
return 0;
}
Is it guarantee that "hello main!" is alayws called before "hello lamda"?
Upvotes: 1
Views: 537
Reputation: 392979
PS I have taken the liberty of threating the question as "Is it guarantee that "hello main!" is alayws called before "hello lamda"?" because "I want to have the guarantee that the handler is executed only after the post()" is trivially true. That's because handlers are guaranteed to only be executed on a thread currently running
run()/poll()
on an execution context
Swatting some syntactical errors and the missing return statement this still has the race condition as described in the comments:
The thread running the io service may return before post
ever gets a chance to run.
There are two typical approaches to solve this:
boost::asio::io_context io;
auto work = make_work_guard(io);
std::thread th{[&io] { io.run(); }};
f(io);
std::cout << "hello main\n";
work.reset();
th.join();
thread_pool
Recent Boost versions introduced a full featured threadpool:
boost::asio::thread_pool io(1); // one thread
f(io.get_executor());
std::cout << "hello main\n";
io.join();
The most direct way is to simply post them all in order:
post(io, [] { std::cout << "hello main\n"; });
f(io.get_executor());
This means that hello main
will always occur before the lambda posted from f
.
If you have a true pool:
boost::asio::thread_pool io(10);
You can use a strand:
auto strand = make_strand(io);
post(strand, [] { std::cout << "hello main\n"; });
f(strand);
This still guarantees the ordering of the tasks in the same way.
Prints
hello main
hello lambda
Upvotes: 2