Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How was coroutine task rescheduled to the main thread, when resumed in another thread?? #28

Open
anlongfei opened this issue Dec 9, 2020 · 4 comments

Comments

@anlongfei
Copy link

anlongfei commented Dec 9, 2020

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 :-)

@andreasbuhr
Copy link
Owner

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

@anlongfei
Copy link
Author

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

image

@andreasbuhr
Copy link
Owner

Trying to reproduce, how do I install clang8 on centos7?

@anlongfei
Copy link
Author

anlongfei commented Dec 14, 2020

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 [email protected]: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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants