After running this program
std::future<int> f() {
std::cout << "enter f on thread " << std::this_thread::get_id() << std::endl;
co_return 1;
}
std::future<void> g() {
std::future<int> i = co_await std::async(f);
std::cout << "resume g on thread: " << std::this_thread::get_id() << std::endl;
co_return;
}
int main() {
std::future<void> f;
while (true) {
f = g();
std::this_thread::sleep_for(1s);
}
return 0;
}
which has been compiled with MSVC 19.43 using the /await
option, I observed that function f
is always being run on the same thread whereas the continuation in function g
is always run on a newly created thread. I also tried to call std::async
with std::launch::async
option to force the creation of a new thread, but still the same same thread would be used to run f
. Can someone explain why?
std::future
shouldn't have a promise type in C++20 coroutines, but that's an MSVC extension.
std::async(f);
executes the function f
in another thread, all mainstream implementations use a thread-pool for std::async, quoting cppref.
(potentially in a separate thread which might be a part of a thread pool)
you would get the same thread id with a normal function, this has nothing to do with coroutines. you could get one of N threads in the pool, usually N is the number of cores, looks like MSVC pool uses the same thread every time when it is not busy.
whereas the continuation in function g is always run on a newly created thread.
yes, MSVC implementation of std::future
awaiter creates a new thread to run the continuation every time, the following code is from MSVC standard library.
void await_suspend(experimental::coroutine_handle<> _ResumeCb) {
// TRANSITION, change to .then if and when future gets .then
thread _WaitingThread([&_Fut = _Fut, _ResumeCb]() mutable {
_Fut.wait();
_ResumeCb();
});
_WaitingThread.detach();
}
a thread is launched and detatched, that's waiting to run the continuation, this happens when awaiting an std::future
to summarize what's happening:
g
, first part of g
runs in main thread until the await.std::async(f)
runs f
in the threadpool.await future
launches a new thread to wait
on the future then run the continuation of g