C++20 协程入门教程

Fri Oct 10 2025

什么是协程

协程是一个函数,它可以暂停以及恢复执行。按照我们对普通函数的理解,函数暂停意味着线程停止运行了(就像命中了断点一样),那协程的不同之处在哪里呢?区别在于,普通函数是线程相关的,函数的状态跟线程紧密关联;而协程是线程无关的,它的状态与任何线程都没有关系。

在调用一个函数的时候,线程的栈上会记录这个函数的状态(参数、局部变量等),这是通过移动栈顶指针来完成的。例如,函数 Foo() 调用 Bar() 的过程如下所示:

<img width="1068" height="430" alt="Image" src="https://github.com/user-attachments/assets/fa987cfd-775d-4c69-98ba-e46fefec56fa" />

当 Bar() 执行完毕,栈顶指针移动回“地址2”, Bar() 的状态被销毁,内存空间被回收。

由此可见,函数状态的维护完全依赖于线程栈,脱离了线程,函数就不复存在,所以说函数是线程相关的。

而协程不一样,协程的状态是保存在堆内存上的。假设 Bar() 是一个协程,那么调用它的过程如下所示:

<img width="1478" height="436" alt="Image" src="https://github.com/user-attachments/assets/050ea8b9-2595-4dd9-a936-a05a32901437" />

首先, Bar() 的状态所需的内存会在堆上分配,独立于线程栈而存在。传递给它的参数都会复制到这个状态中,而局部变量会直接在这个状态中创建。调用 Bar() 的时候,由于本质上还是一个函数调用,所以栈顶指针也会往下移动,在栈上给执行 Bar() 所需的状态分配空间,其中会有一个引用指向在堆上的状态,这样一来, Bar() 就可以像一个普通函数那样执行了,线程也可以访问到位于堆上的状态。

如果协程需要暂停,那么当前执行到的代码位置会记录到堆的状态中。然后栈上的执行时状态被销毁,栈顶指针移动以回收空间,就像普通函数结束时那样。在下一次恢复执行时,堆状态中记录的暂停位置会读取出来,从这个位置接着执行。这样就实现了一个可暂停和恢复执行的函数。

由此可见,当协程执行的时候,它跟普通函数一样,也是需要依赖线程栈;但是,一旦它暂停了,它的状态就会独立保存在堆中,此时它跟任何线程都没有关系,调用它的线程可以继续去做其它事情而不会停止。在下一次恢复执行时,协程可以由上次执行的线程来执行,也可以由另外一个完全不同的线程来执行。所以说协程是线程无关的。

参考文献

C++20协程入门教程


Comments

There are no comments yet.