chriskohlhoff/asio

`boost::asio::thread_pool` `attach()`/`join()` race condition

Opened this issue · 0 comments

This is somewhat related to an issue I reported a while ago: #1230

The following code has a potential deadlock:

asio::thread_pool pool(0);
std::thread thread([&pool]() { pool.attach(); });
pool.join();
thread.join();

The reason is the implementation of thread_pool::join():

void thread_pool::join()
{
  if (num_threads_)
    scheduler_.work_finished();

  if (!threads_.empty())
    threads_.join();
}

The problem is the first conditional -- as attach() happens in a separate thread, it can happen after the first if check. In that case num_threads_ was 0 & scheduler_.work_finished() never got called. Both threads get stuck because attach() never returns.

Now, calling pool.wait() instead of pool.join() fixes the problem as it calls scheduler_.work_finished() unconditionally.

Documentation for both join() & wait() is the same, but from the implementation it looks like

  • join() will only stop threads if there are any attached & doesn't bother with threads about to attach
  • wait() will stop currently attached threads & any that might attach in the future

I'm having trouble understanding this if condition. Would it be wrong to call scheduler_.work_finished() even if number of threads seems to be 0?

Ideally for me the implementation for join would be:

void thread_pool::join() { wait(); }