c++ - "With a stackless coroutine, only the top-level routine may be suspended."是什么意思

标签 c++ coroutine c++20 c++-coroutine

我从 here 中找到了那个声明.起初我很惊讶,因为我相信这使得无堆栈协程几乎毫无用处(而且 C++ 协程 TS 是无堆栈的)。所以我写了一个demo(在visual studio中使用C++协程TS):

#include<experimental/coroutine>
#include<iostream>
#include<thread>
#include<mutex>
#include<future>
#include<chrono>

using namespace std;
using namespace std::chrono;
using namespace std::experimental;

class AsyncQueue {
public:
    class Awaitable {
        friend AsyncQueue;
        AsyncQueue& mQueue;
        coroutine_handle<> mCoroutineHandle;
        Awaitable* mNext = nullptr;
    public:
        Awaitable(AsyncQueue& queue):mQueue(queue){}

        bool await_ready() const noexcept {
            return false;
        }

        bool await_suspend(coroutine_handle<> coroutineHandle) noexcept
        {
            mCoroutineHandle = coroutineHandle;
            mQueue.enqueue(this);
            return true;
        }

        void await_resume() noexcept {}
    };
private:
    mutex mMutex;
    Awaitable* mHead = nullptr;
    Awaitable* mTail = nullptr;
    void enqueue(Awaitable* awaitable){
        lock_guard<mutex> g{ mMutex };
        if (mTail) {
            mTail->mNext = awaitable;
            mTail = awaitable;
        }
        else {
            mTail = awaitable;
            mHead = mTail;
        }
    }

    Awaitable* dequeue() {
        lock_guard<mutex> g{ mMutex };
        Awaitable* result = mHead;
        mHead = nullptr;
        mTail = nullptr;
        return result;
    }

public:
    Awaitable operator co_await() noexcept {
        return Awaitable{ *this };
    }

    bool poll() {
        Awaitable* awaitables = dequeue();
        if (!awaitables) {
            return false;
        }
        else {
            while (awaitables) {
                awaitables->mCoroutineHandle.resume();
                awaitables = awaitables->mNext;
            }
            return true;
        }
    }
};


AsyncQueue toBackgroundThread;
AsyncQueue toMainThread;

std::future<void> secondLevel(int id)
{
    co_await toBackgroundThread;
    cout << id << " run on " << this_thread::get_id() << endl;
    co_await toMainThread;
    cout << id << " run on " << this_thread::get_id() << endl;
}

std::future<void> topLevel() {
    co_await secondLevel(1);
    co_await secondLevel(2);
}

void listen(AsyncQueue& queue) {
    while (true) {
        if (!queue.poll()) {
            this_thread::sleep_for(100ms);
        }
    }
}

int main() {
    thread([]() {
        listen(toBackgroundThread);
    }).detach();

    topLevel();

    listen(toMainThread);
}

coroutine topLevel 调用两个 secondLevel(我认为它们是可挂起的非顶级例程),并且工作正常。 上面的代码打印:

1 run on 16648
1 run on 3448
2 run on 16648
2 run on 3448

根据该回答,这禁止在通用库中的例程中提供暂停/恢复操作。我在这里没有看到任何禁令。

最佳答案

在每次调用co_await时,只有顶层协程被挂起。要挂起较低级别,该级别 必须显式挂起自己。到那时,它就是当前的“顶级”。所以在任何情况下,只有当前的顶层被暂停。

将其与一个纯粹假设的堆栈协程库进行比较:

//This function will always print the same thread ID.
void secondLevel(int id)
{
    while(!toBackgroundThread.poll())
      suspend_coroutine();

    cout << id << " run on " << this_thread::get_id() << endl;

    while(!toBackgroundThread.poll())
      suspend_coroutine();

    cout << id << " run on " << this_thread::get_id() << endl;
}

void topLevel() {
    secondLevel(1);
    secondLevel(2);
}

void listen(AsyncQueue& queue) {
    while (true) {
        if (!queue.poll()) {
            this_thread::sleep_for(100ms);
        }
    }
}

int main() {
    thread([]() {
        listen(toBackgroundThread);
    }).detach();

    auto coro = create_coroutine(topLevel);
    coro.switch_to();

    toMainThread.ready(); //Notes that the main thread is waiting
    while (true) {
        if (!toMainThread.poll()) {
            coro.switch_to();
        }
    }
};

topLevel 没有任何明确的暂停机制。然而,只要它调用的任何函数暂停执行,它的执行就会暂停。由赋予 create_coroutine 的函数定义的整个调用堆栈及其调用的所有内容都会暂停。这就是堆栈协程的工作原理。

当谈到无堆栈协程时,这就是对比。在无堆栈版本中,每个需要暂停的函数都必须专门编码才能这样做。因此不再是真正的“通用”;它现在专门用于暂停场景。

关于c++ - "With a stackless coroutine, only the top-level routine may be suspended."是什么意思,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52924380/

相关文章:

C++20 | std::is_constant_evaluate() 和 const 变量

时间:2019-03-17 标签:c++coroutinesfinal_suspendforpromise_type

使用 vector 推回和迭代器时出现 C++ 运行时错误

c++ - 我想在 Windows 下使用 C++ 以某种基本方式表示西里尔字符

c++ - 是否可以将此 Rust 代码写入语义上等效的 C++ 代码?

multithreading - 当 Goroutines 切换时,CPU 上下文会发生什么?

c++ - POSIX/UNIX : How to reliably close a file descriptor

kotlin - 将协程函数作为函数参数传递

python - Eventlet 和 Python 守护进程,Foo 没有被调用?

c++ - gcc 和 clang 在表达式是否为常量的问题上存在分歧