main h1=00000000 h2=00000000 main h1=009B0048 h2=00000000 main h1=009B0048 h2=009C0078 main h1=009B0048 h2=009C0078 coroutine: 0 @ 009B005C coroutine: 9 @ 009C008C main h1=009B0048 h2=009C0078 coroutine: 1 @ 009B005C coroutine: 10 @ 009C008C main h1=009B0048 h2=009C0078 coroutine: 2 @ 009B005C coroutine: 11 @ 009C008C // cr_func是协程函数。main里启动了两个协程,参数不同 // 协程里printf("coroutine: %2d @ %p\n", i++, &i); int main() { HCR h1, h2; printf("main h1=%p h2=%p\n", h1, h2); cr_func(&h1, 0); printf(" main h1=%p h2=%p\n", h1, h2); cr_func(&h2, 9); printf(" main h1=%p h2=%p\n", h1, h2); for (int i = 0; i < 3; ++i) { printf(" main h1=%p h2=%p\n", h1, h2); h1.resume(), h2.resume(); } h2.destroy(), h1.destroy(); }
勾起兴趣再往下看:
struct awaitable : public std::suspend_always { HCR* m_phcr; awaitable(HCR* phcr) : m_phcr(phcr) {} void await_suspend(HCR new_handle) { *m_phcr = new_handle; } }; cr_ret_type cr_func(HCR* phcr, int i) { char data[65536]; awaitable a(phcr); // *phcr = new_handle;修改的是main里的handle. while (1) { co_await a; // 干3件事: // 1. Save all local variables (如data) and "jmp_buf" to a heap-allocated object. // 2. "setjmp", 设置一个"书签", 以后再"longjmp"跳回来继续执行(resume)。官话: // Create a new coroutine handle X and pass it to a.await_suspend(). // HCR是the heap-allocated object的句柄,是个void*, 黑盒子能用不能看。 // 3. "return" // resume回来后执行"return"后的下一条语句。 // jmp_buf ~= 数据寄存器和instruction pointer/program counter. 局部变量宜只放个指针: // struct big_data* pdata; printf("coroutine: %2d @ %p\n", i++, &i); } }
丑陋的东西在最后:
typedef std::coroutine_handle<> HCR; struct cr_ret_type { struct promise_type { cr_ret_type get_return_object() { return {}; } std::suspend_never initial_suspend() { return {}; } std::suspend_never final_suspend() noexcept { return {}; } void unhandled_exception() {} }; }; // https://www.scs.stanford.edu/dm/blog/c++-coroutines.html // g++ -fcoroutines crdemo.cpp (gcc 10.2或更高版; tdm-gcc-10.3.0.exe ok) #include <coroutine> #include <stdio.h>
协程必须返回cr_ret_type,void cr_func()是不行的。cr_ret_type里的东西不要改。可以像python那样做生成器。