Elvis Dukaj
Elvis Dukaj

Reputation: 7368

Boost.Asio is the handler called after that the post?

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

Answers (1)

sehe
sehe

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:

Using a work guard

Live On Coliru

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();

Using the thread_pool

Recent Boost versions introduced a full featured threadpool:

Live On Coliru

boost::asio::thread_pool io(1); // one thread

f(io.get_executor());
std::cout << "hello main\n";

io.join();

Ordering Tasks: Single Service Thread

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.

Ordering: Multiple Service Threads

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.

Live On Coliru

Prints

hello main
hello lambda

Upvotes: 2

Related Questions