没有合适的资源?快使用搜索试试~ 我知道了~
05栈的魔法:从栈切换的角度理解进程和协程1
需积分: 0 0 下载量 189 浏览量
2022-08-03
22:52:34
上传
评论
收藏 6.8MB PDF 举报
温馨提示
![preview](https://dl-preview.csdnimg.cn/86313806/0001-9472cfd09ac0bb610db65e3eee95bcf2_thumbnail.jpeg)
![preview-icon](https://csdnimg.cn/release/downloadcmsfe/public/img/scale.ab9e0183.png)
试读
18页
通过今天的学习,你将掌握协程的基本知识,这样,你在 C++ 中使用各种协程库,或者在Lua、Go 等语言中使用原生协程的时候,就能理解它们背后发生了什么,也可以
资源推荐
资源详情
资源评论
![txt](https://img-home.csdnimg.cn/images/20210720083642.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![txt](https://img-home.csdnimg.cn/images/20210720083642.png)
![docx](https://img-home.csdnimg.cn/images/20210720083331.png)
![rar](https://img-home.csdnimg.cn/images/20210720083606.png)
![rar](https://img-home.csdnimg.cn/images/20210720083606.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![rar](https://img-home.csdnimg.cn/images/20210720083606.png)
![zip](https://img-home.csdnimg.cn/images/20210720083736.png)
![pdf](https://img-home.csdnimg.cn/images/20210720083512.png)
![docx](https://img-home.csdnimg.cn/images/20210720083331.png)
![pdf](https://img-home.csdnimg.cn/images/20210720083512.png)
![](https://csdnimg.cn/release/download_crawler_static/86313806/bg1.jpg)
2021/11/7 05 | 栈的魔法:从栈切换的角度理解进程和协程
https://time.geekbang.org/column/article/435493 1/18
05 | 栈的魔法:从栈切换的角度理解进程和协程
2021-11-03 海纳
《编程高手必学的内存知识》
课程介绍
讲述:海纳
时长 20:25 大小 18.70M
你好,我是海纳。
上一节课,我们了解到函数在执行的时候,就会在栈上创建栈帧,那么函数执行的上下文
都将保存在栈帧里。今天,我们就再来进一步分析,栈切换在计算机系统设计中所发挥的
重要作用。
几乎所有的程序员都会遇到并发程序。因为多进程或者多线程程序可以并发执行,充分利
用多 CPU 多核的计算资源来完成任务,会大大提升应用程序的性能。
下载APP
![](https://csdnimg.cn/release/download_crawler_static/86313806/bg2.jpg)
2021/11/7 05 | 栈的魔法:从栈切换的角度理解进程和协程
https://time.geekbang.org/column/article/435493 2/18
所以,我相信你在工作中也遇到过多线程程序,但不知道你是否考虑过进程和线程是如何
切换的呢?很多文章都介绍了,操作系统为了避免频繁进入内核态,会把很多工作都尽量
放在用户态。那么你有没有仔细思考过内核态、用户态到底意味着什么呢?
要回答上面的问题,我们就要理解这些概念背后最重要的一个步骤:对执行单元的上下文
环境进行切换。它就是由栈这个核心数据结构支撑的,这也是我们今天学习的重点内容。
通过今天的学习,你将掌握协程的基本知识,这样,你在 C++ 中使用各种协程库,或者在
Lua、Go 等语言中使用原生协程的时候,就能理解它们背后发生了什么,也可以帮你写出
正确的 IO 程序。你还将深入理解操作系统用户态和内核态,这样,你在做架构的时候,就
能正确评估操作系统进入内核态的开销是多少。
在讲解执行单元的切换与栈的关系之前,我们先来给出它的准确定义。
什么是执行单元
执行单元是指 CPU 调度和分派的基本单位,它是一个 CPU 能正常运行的基本单元。执行
单元是可以停下来的,只要能把 CPU 状态(其实就是寄存器的值)全部保存起来,等到这
个执行单元再被调度的时候,就把状态恢复过来就行了。我们把这种保存状态,挂起,恢
复执行,恢复状态的完整过程,称为执行单元的调度 (Scheduling)。
具体来说,常见的执行单元有进程,线程和协程三种,接下来,我们详细说明这三种执行
单元的区别和联系。我们先来比较进程和线程。
理解进程和线程
当运行一个可执行程序的时候,操作系统就会启动一个进程。进程会被操作系统管理和调
度,被调度到的进程就可以独占 CPU 了。
CPU 就像是一个可以轮流使用的工作台,多个进程可以在工作台上工作,时间到了就会带
着自己的工作离开工作台,换下一个进程上来工作。
进程有自己独立的内存空间和页表,以及文件表等等各种私有资源,如果使用多进程系
统,让多个任务并发执行,那么它所占用的资源就会比较多。线程的出现解决了这个问
题。
![](https://csdnimg.cn/release/download_crawler_static/86313806/bg3.jpg)
2021/11/7 05 | 栈的魔法:从栈切换的角度理解进程和协程
https://time.geekbang.org/column/article/435493 3/18
同一个进程中的线程则共享该进程的内存空间,文件表,文件描述符等资源,它与同一个
进程的其他线程共享资源分配。除了共享的资源,每个线程也有自己的私有空间,这就是
线程的栈。线程在执行函数调用的时候,会在自己的线程栈里创建函数栈帧。
根据上面所说的特点,人们常把进程看做是资源分配的单位,把线程才看成一个具体的执
行实体。
由于线程的切换过程和进程的切换过程十分相似,我们这节课就只以进程的切换为重点进
行讲解,请你一定要自己查找相关资料,对照进程切换的过程,去理解线程的切换过程。
理解协程
协程是比线程更轻量的执行单元。进程和线程的调度是由操作系统负责的,而协程则是由
执行单元相互协商进行调度的,所以它的切换发生在用户态。只有前一个协程主动地执行
yield 函数,让出 CPU 的使用权,下一个协程才能得到调度。
因为程序自己负责协程的调度,所以大多数时候,我们可以让不那么忙的协程少参与调
度,从而提升整个程序的吞吐量,而不是像进程那样,没有繁重任务的进程,也有可能被
换进来执行。
协程的切换和调度所耗费的资源是最少的,Go 语言把协程和 IO 多路复用结合在一起,提
供了非常便捷的 IO 接口,使得协程的概念深入人心。
从操作系统和 Web Server 演进的历史来看,先是多进程系统的出现,然后出现了多线程
系统,最后才是协程被大规模使用,这个演进历程背后的逻辑就是执行单元需要越来越轻
量,以支持更大的并发总数。
但我们这节课却要先讲协程,这是因为从实现层面来说,协程是最简单的,当你理解了协
程的实现原理,再回头学习进程就比较容易了,所以我们先来学习协程的原理。
协程是怎么调度和切换的?
在讲解协程的理论之前,我们先通过一个最简单的协程的例子,来观察协程的运作机制:
复制代码
1
#include <stdio.h>
![](https://csdnimg.cn/release/download_crawler_static/86313806/bg4.jpg)
2021/11/7 05 | 栈的魔法:从栈切换的角度理解进程和协程
https://time.geekbang.org/column/article/435493 4/18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <stdlib.h>
#define STACK_SIZE 1024
typedef void(*coro_start)();
class coroutine {
public:
long* stack_pointer;
char* stack;
coroutine(coro_start entry) {
if (entry == NULL) {
stack = NULL;
stack_pointer = NULL;
return;
}
stack = (char*)malloc(STACK_SIZE);
char* base = stack + STACK_SIZE;
stack_pointer = (long*) base;
stack_pointer -= 1;
*stack_pointer = (long) entry;
stack_pointer -= 1;
*stack_pointer = (long) base;
}
~coroutine() {
if (!stack)
return;
free(stack);
stack = NULL;
}
};
coroutine* co_a, * co_b;
void yield_to(coroutine* old_co, coroutine* co) {
__asm__ (
"movq %%rsp, %0\n\t"
"movq %%rax, %%rsp\n\t"
:"=m"(old_co->stack_pointer):"a"(co->stack_pointer):);
}
void start_b() {
printf("B");
yield_to(co_b, co_a);
printf("D");
yield_to(co_b, co_a);
}
int main() {
剩余17页未读,继续阅读
资源评论
![avatar-default](https://csdnimg.cn/release/downloadcmsfe/public/img/lazyLogo2.1882d7f4.png)
![avatar](https://profile-avatar.csdnimg.cn/2a7674b4f3c64eb6baaecb9205aa62db_weixin_35742195.jpg!1)
豆瓣时间
- 粉丝: 23
- 资源: 329
上传资源 快速赚钱
我的内容管理 展开
我的资源 快来上传第一个资源
我的收益
登录查看自己的收益我的积分 登录查看自己的积分
我的C币 登录后查看C币余额
我的收藏
我的下载
下载帮助
![voice](https://csdnimg.cn/release/downloadcmsfe/public/img/voice.245cc511.png)
![center-task](https://csdnimg.cn/release/downloadcmsfe/public/img/center-task.c2eda91a.png)
安全验证
文档复制为VIP权益,开通VIP直接复制
![dialog-icon](https://csdnimg.cn/release/downloadcmsfe/public/img/green-success.6a4acb44.png)