gpt4 book ai didi

c++ - 恢复 ASIO Stackless 协程

转载 作者:太空宇宙 更新时间:2023-11-04 12:45:48 25 4
gpt4 key购买 nike

在对 Clang 中的协程 TS 的当前实现进行了一些尝试后,我偶然发现了 asio 无堆栈协程实现。它们被描述为 Portable Stackless Coroutines in One* Header .主要处理异步代码,我也想尝试一下。

main 中的协程 block 函数应等待函数中生成的线程异步设置的结果 foo .但是我不确定如何让执行在 <1> 点继续(在 yield 表达式之后)一旦线程设置了值。

使用协程 TS 我会调用 coroutine_handle , 然而 boost::asio::coroutine似乎不可调用。

这甚至有可能使用 boost::asio::coroutine

#include <thread>
#include <chrono>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/yield.hpp>
#include <cstdio>

using namespace std::chrono_literals;
using coroutine = boost::asio::coroutine;

void foo(coroutine & coro, int & result) {
std::thread([&](){
std::this_thread::sleep_for(1s);
result = 3;
// how to resume at <1>?
}).detach();
}

int main(int, const char**) {
coroutine coro;
int result;
reenter(coro) {
// Wait for result
yield foo(coro, result);
// <1>
std::printf("%d\n", result);
}

std::thread([](){
std::this_thread::sleep_for(2s);
}).join();
return 0;
}

谢谢你的帮助

最佳答案

首先,stackless 协程更适合描述为可恢复函数。您当前遇到的问题是使用 main.如果将逻辑提取到单独的仿函数中,则可能:

class task; // Forward declare both because they should know about each other
void foo(task &task, int &result);

// Common practice is to subclass coro
class task : coroutine {
// All reused variables should not be local or they will be
// re-initialized
int result;

void start() {
// In order to actually begin, we need to "invoke ourselves"
(*this)();
}

// Actual task implementation
void operator()() {
// Reenter actually manages the jumps defined by yield
// If it's executed for the first time, it will just run from the start
// If it reenters (aka, yield has caused it to stop and we re-execute)
// it will jump to the right place for you
reenter(this) {
// Yield will store the current location, when reenter
// is ran a second time, it will jump past yield for you
yield foo(*this, result);
std::printf("%d\n", result)
}
}
}

// Our longer task
void foo(task & t, int & result) {
std::thread([&](){
std::this_thread::sleep_for(1s);
result = 3;
// The result is done, reenter the task which will go to just after yield
// Keep in mind this will now run on the current thread
t();
}).detach();
}

int main(int, const char**) {
task t;

// This will start the task
t.start();

std::thread([](){
std::this_thread::sleep_for(2s);
}).join();
return 0;
}

请注意,不可能从子函数中产生。这是无堆栈协程的局限性。

工作原理:

  • yield 存储一个唯一标识符以跳转到协程内部
  • yield 将运行你放在它后面的表达式,应该是一个异步调用,否则不会有什么好处
  • 运行后会跳出重入 block 。

现在“启动”完成,您启动另一个线程等待。同时,foo 的线程结束 sleep 并再次调用您的任务。现在:

  • reenter block 将读取协程的状态,发现它必须跳过 foo 调用
  • 您的任务将继续,打印结果并退出函数,返回到 foo 线程。

foo 线程现已完成,main 可能仍在等待第二个线程。

关于c++ - 恢复 ASIO Stackless 协程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51720267/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com