步骤 6 / 7
返回用户态,以及这一趟的代价
内核带着结果切回用户态;但每次进出内核都不便宜。
内核做完后切回用户态,程序从停下的地方继续,并拿到结果(写了几个字节)。 进出内核比普通函数调用慢得多,所以 printf 会先把文字攒在缓冲区,攒够了再调用一次 write,就像前端把多个请求合并成一次。 用 strace 对比一下“逐字写”和“缓冲后写”,系统调用次数差别很明显。
操作系统
程序不能直接碰硬件,想读写文件、上网、打印,都得通过“系统调用”这扇门请内核代办。
以 Linux(x86-64)上一个程序往终端打印一行字为例。
步骤 6 / 7
内核带着结果切回用户态;但每次进出内核都不便宜。
内核做完后切回用户态,程序从停下的地方继续,并拿到结果(写了几个字节)。 进出内核比普通函数调用慢得多,所以 printf 会先把文字攒在缓冲区,攒够了再调用一次 write,就像前端把多个请求合并成一次。 用 strace 对比一下“逐字写”和“缓冲后写”,系统调用次数差别很明显。
| 当前状态 | 发生了什么 |
|---|---|
| 用户态 | 程序想打印文字,但无权直接操作硬件 |
| 用户态 | 程序发起 write 系统调用 |
| 用户态 → 内核态 | CPU 切换模式,内核接手 |
| 内核态 | 检查参数,通过后驱动硬件完成输出 |
| 内核态 | 请求不合法,返回错误码 |
| 内核态 → 用户态 | 带着结果返回,程序继续执行 |