Search code examples
c++c++20c++-coroutinecppcoro

Understanding scheduling of coroutine


The scheduling of coroutine on execution context, as done e.g. through lewissbaker/cppcoro/schedule_on puzzles me.

I think I understand the simpler case of executing regular (i.e. non-coroutine) code after co-awaiting a scheduler, such as [ref]

cppcoro::task<std::string> do_something_on_threadpool(cppcoro::static_thread_pool& tp)
{
  // First schedule the coroutine onto the threadpool.
  co_await tp.schedule();

  // When it resumes, this coroutine is now running on the threadpool.
  do_something();
}

Which I can relate to the cppreference "switch_to_new_thread " example on the coroutines page.

However, I cannot get my head around a code snippet like

cppcoro::task<std::string> do_something_on_threadpool(cppcoro::static_thread_pool& tp)
{
  // First schedule the coroutine onto the threadpool.
  co_await tp.schedule();

  co_await wait_for_something();

  do_something();
}

Which when I tested it worked as expected: do_something() was executed on the thread pool.

If I understand correctly, the coroutine is resumed on the thread before hitting co_await wait_for_something();. What happens then? Since the coroutine was resumed on thread pool by a regular function, how can it co_await?


Solution

  • I'm going to assume that wait_for_something is also a cppcoro::task (or something who's promise type has std::suspend_always initial_suspend()), who's body doesn't do any thread switching.

    co_await wait_for_something(); does the following things:

    • The coroutine state for wait_for_something is created (in a suspended state).
      • This corresponds to the wait_for_something()
    • The std::coroutine_handle associated with do_something_on_threadpool is passed to the promise associated with wait_for_something() via the await_suspend member
      • It is up to the coroutine machinery of wait_for_something to put this somewhere, for it to be resumed when wait_for_something finishes. That resume will proceed on to do_something()
    • wait_for_something is resumed
      • Those steps correspond to the co_await