How was coroutine task rescheduled to the main thread, when resumed in another thread??
anlongfei opened this issue · 4 comments
class MyAwaiter {
public:
bool await_ready() {
return false;
}
void await_suspend(std::experimental::coroutine_handle<> continuation) noexcept {
std::thread([c = continuation]() mutable {
c.resume(); // resume coroutine in a new thread.
std::cout << "new thread: " << std::this_thread::get_id() << std::endl;
}).detach();
}
void await_resume() {}
};
TEST_CASE("task doesn't start until awaited")
{
std::cout << "main thread " << std::this_thread::get_id() << std::endl;
auto func = [&]() -> cppcoro::task<> {
std::cout << "before: " << std::this_thread::get_id() << std::endl;
co_await MyAwaiter();
std::cout << "after: " << std::this_thread::get_id() << std::endl;
co_return;
};
cppcoro::sync_wait([&]() -> cppcoro::task<>
{
auto t = func();
co_await t;
}());
}
output like this
main thread 140301651535680
before: 140301651535680
new thread: 140300609353472
after: 140301651535680
As far as I know, the couroutine task func would resumed in a detached thread, so after: 140301651535680
id would be the same as new thread: 140300609353472
.
but the output is unexpected, so what happened with c.resume();
)-:?
Thx :-)
Interesting. What compiler are you using? Could you please try the following code with a little more output?
#include <coroutine>
#include <thread>
#include <iostream>
#include <cppcoro/task.hpp>
#include <cppcoro/sync_wait.hpp>
class MyAwaiter {
public:
bool await_ready() {
return false;
}
void await_suspend(cppcoro::coroutine_handle<> continuation) noexcept {
std::thread([c = continuation]() mutable {
std::cout << "new thread created: " << std::this_thread::get_id() << std::endl;
c.resume(); // resume coroutine in a new thread.
std::cout << "new thread after resume: " << std::this_thread::get_id() << std::endl;
}).detach();
}
void await_resume() {}
};
int main() {
std::cout << "main thread " << std::this_thread::get_id() << std::endl;
auto func = [&]() -> cppcoro::task<> {
std::cout << "coroutine before co_await: " << std::this_thread::get_id() << std::endl;
co_await MyAwaiter();
std::cout << "coroutine after co_await:" << std::this_thread::get_id() << std::endl;
co_return;
};
std::cout << "main thread before sync_wait:" << std::this_thread::get_id() << std::endl;
cppcoro::sync_wait([&]() -> cppcoro::task<> {
std::cout << "top level coroutine start " << std::this_thread::get_id() << std::endl;
auto t = func();
std::cout << "top level coroutine before co_await " << std::this_thread::get_id() << std::endl;
co_await t;
std::cout << "top level coroutine after co_await " << std::this_thread::get_id() << std::endl;
}());
std::cout << "main thread after sync_wait:" << std::this_thread::get_id() << std::endl;
}
On my system I get, as expected:
main thread 139736076810048
main thread before sync_wait:139736076810048
top level coroutine start 139736076810048
top level coroutine before co_await 139736076810048
coroutine before co_await: 139736076810048
new thread created: 139736076805888
coroutine after co_await:139736076805888
top level coroutine after co_await 139736076805888
new thread after resume: 139736076805888
main thread after sync_wait:139736076810048
cppcoro lib with this patch:(top commit id is a87e97f)
diff --git a/test/task_tests.cpp b/test/task_tests.cpp
index 96b821a..656f201 100644
--- a/test/task_tests.cpp
+++ b/test/task_tests.cpp
@@ -15,10 +15,51 @@
#include <string>
#include <type_traits>
+#include <iostream>
+#include <thread>
#include "doctest/doctest.h"
TEST_SUITE_BEGIN("task");
+class MyAwaiter
+{
+public:
+ bool await_ready() { return false; }
+
+ void await_suspend(std::experimental::coroutine_handle<> continuation) noexcept
+ {
+ std::thread([c = continuation]() mutable {
+ std::cout << "new thread created: " << std::this_thread::get_id() << std::endl;
+ c.resume(); // resume coroutine in a new thread.
+ std::cout << "new thread after resume: " << std::this_thread::get_id() << std::endl;
+ }).detach();
+ }
+
+ void await_resume() {}
+};
+
+TEST_CASE("test")
+{
+ std::cout << "main thread " << std::this_thread::get_id() << std::endl;
+ auto func = [&]() -> cppcoro::task<> {
+ std::cout << "coroutine before co_await: " << std::this_thread::get_id() << std::endl;
+ co_await MyAwaiter();
+ std::cout << "coroutine after co_await:" << std::this_thread::get_id() << std::endl;
+ co_return;
+ };
+ std::cout << "main thread before sync_wait:" << std::this_thread::get_id() << std::endl;
+ cppcoro::sync_wait([&]() -> cppcoro::task<> {
+ std::cout << "top level coroutine start " << std::this_thread::get_id() << std::endl;
+ auto t = func();
+ std::cout << "top level coroutine before co_await " << std::this_thread::get_id()
+ << std::endl;
+ co_await t;
+ std::cout << "top level coroutine after co_await " << std::this_thread::get_id()
+ << std::endl;
+ }());
+ std::cout << "main thread after sync_wait:" << std::this_thread::get_id() << std::endl;
+}
+
TEST_CASE("task doesn't start until awaited")
{
bool started = false;
my compiler isclang/llvm-8.0.1
.On centos7
, the output is unexpected :(
main thread 140019514656576
main thread before sync_wait:140019514656576
top level coroutine start 140019514656576
top level coroutine before co_await 140019514656576
coroutine before co_await: 140019514656576
new thread created: 140018492016384
coroutine after co_await:140019514656576
top level coroutine after co_await 140019514656576
new thread after resume: 140018492016384
main thread after sync_wait:140019514656576
Trying to reproduce, how do I install clang8 on centos7?
Two ways to get clang8:
1.get clang8 binary from https://releases.llvm.org/download.html#8.0.1
2.build from source code
reference:https://github.com/llvm/llvm-project
git clone git@github.com:llvm/llvm-project.git -b release/8.x \
&& mkdir build \
&& cmake -G Ninja ../llvm-project/llvm -DLLVM_ENABLE_PROJECTS="clang;llvm" -DCMAKE_INSTALL_PREFIX=<path-to-install> -DCMAKE_BUILD_TYPE=Release \
&& ninja install
replace <path-to-install>
with where you want to install clang8 binary.