异步编程杂记
还记得在最开始学习单片机开发时,我经常写出这样的程序:
int main() {
do_task_a();
do_task_b();
do_task_c();
// ......
return 0;
}
到了后来在 Linux/Windows 下进行程序开发的时候,了解到了多进程,多线程的概念。原来我可以编写一段代码,让CPU同一时刻干多个任务(即使是单核CPU,宏观情况下也是同一时刻可以执行多个任务)。
以多线程开发为例,当然,多线程和异步编程是两种不同的并发处理机制,它们可以结合使用,但本质并不等同。多线程(Multithreading)是操作系统级别的并发机制,通过创建多个线程(轻量级进程)实现并行或并发执行。正式因为这样,所以在新手时期,很容易写出应用程序创建了多个线程,而目的仅仅是为了能够使多个逻辑能够分别执行而不受其他逻辑影响。但是滥用线程,造成线程数量过多,会给系统带来负担(特别是像RTOS)。同时也会带来数据竞争的风险。
simonbrunel/qtpromise: Promises/A+ implementation for Qt/C++
协程分为无栈协程和有栈协程两种,无栈指可挂起/恢复的函数,有栈协程则相当于用户态线程。有栈协程切换的成本是用户态线程切换的成本,而无栈协程切换的成本则相当于函数调用的成本。
无栈协程和线程的区别:无栈协程只能被线程调用,本身并不抢占内核调度,而线程则可抢占内核调度。
无栈协程是一个可以暂停和恢复的函数,是函数调用的泛化。
我们知道一个函数的函数体(function body)是顺序执行的,执行完之后将结果返回给调用者,我们没办法挂起它并稍后恢复它,只能等待它结束。而无栈协程则允许我们把函数挂起,然后在任意需要的时刻去恢复并执行函数体,相比普通函数,协程的函数体可以挂起并在任意时刻恢复执行。
awaiter
在 C++ 协程中,通过 co_await
表达式生成的 awaiter
对象会被编译器自动存储在协程帧(coroutine frame)中。这是为了确保协程在挂起(suspend)期间,awaiter
对象仍然有效,并在恢复(resume)时能够正确完成异步操作。
awaitable