boost.png (6897 bytes) Home Libraries People FAQ More


Coroutines and thread safety

Boost.Coroutine provides a restricted version of the distinct objects thread safety guarantee. The library is thread safe as long as these preconditions are valid:

  1. All member functions of a coroutine can only be called from the owning thread (the thread where a coroutine has been created is said to be the owning thread; creating a coroutine means invoking any constructor).
  2. Distinct coroutine instances can be freely called from different threads.

It follows from 1 that:

What does this means in practice

In practice a coroutine cannot migrate from one thread to another. For its whole lifetime it is bound to one specific thread. Other threads cannot safely access any coroutine member functions.

Not even locking can be safely used to protect concurrent accesses to a coroutine. That is two treads cannot invoke the same coroutine even if the serialize access through a mutex.

If coroutines are, for example, used to implement a M on N threading models (M coroutines on N threads with N < M), coroutines cannot be dynamically migrated from a more loaded thread to a less loaded threads.

Threads and Boost.Asio

From the threads guarantees of Boost.Coroutine, it follows that, if coroutines are ever inserted in an asio::io_service, no more than one thread can call io_service::run(). This thread must be the one that created all coroutines inserted in the io_service.

This means that the "one io_service per thread" scheme must be used.

This means that on Windows platforms an application cannot take advantage of the ability of a Win32 completion port to balance the load across all threads bound to it. This might incur, in some applications, in a performance penalty. On the other hand the thread affinity of coroutines might result in better CPU affinity and thus a better cache utilization and memory usage especially on NUMA SMP systems.

Relaxing requirements

In the future, as more experience with the library is gained, the thread safety restrictions could be slightly relaxed. It is likely that the owning thread will become the first one to invoke operator() for that coroutine or yield_to that coroutine.

It is unlikely that thread migration will ever be possible (nor it is believed to be a necessary feature).

For a rationale for the current requirements see "Interaction between coroutines and threads".

Copyright 2006 Giovanni P. Deretta