什么是上下文切换?进程切换时 CPU 到底在保存什么

这是"操作系统系列教程"的第十九篇。前面几篇我们讲了进程调度、时间片轮转、优先级调度,知道了操作系统如何在多个进程之间分配 CPU。但还有一个关键问题没有回答:当一个进程被换下、另一个进程被换上时,CPU 到底做了什么?那些被中断的进程,它们的执行状态是怎么保存的?答案就是------上下文切换。

一个"接电话"的类比

你正在写代码,突然手机响了。你放下代码,接起电话,聊了十分钟,挂断电话,然后回到电脑前,从刚才停下的地方继续写。

这个过程中,你的大脑做了几件事:

  1. 记住当前进度:刚才写到哪一行、光标在哪个位置、下一步想写什么;
  2. 保存思维状态:刚才思考的思路、正在调试的 bug、脑海里的一些临时变量;
  3. 切换到电话模式:开始和对方交流;
  4. 恢复之前的进度:挂断电话后,回到刚才写到的位置,继续思考。

操作系统在切换进程时,做的事情几乎一模一样。它需要保存当前进程的执行状态,恢复下一个进程的执行状态。这个过程,就是上下文切换(Context Switch)。

上下文切换是多任务操作系统的核心机制。没有它,多个进程就无法"同时"运行;但切换太频繁,又会带来巨大的性能开销。理解上下文切换,是理解操作系统并发执行的关键。

这篇文章,我们就来把"上下文切换"这件事讲清楚。

说明:本文涉及寄存器、程序计数器、页表、TLB 等概念。初学者如果遇到暂时看不懂的术语,可以先跳过细节,重点理解"上下文切换就是保存当前进程状态、恢复下一个进程状态的过程"这一核心思想。

一、上下文切换到底是什么?

1.1 从"上下文"说起

要理解上下文切换,先要理解什么是上下文(Context)。

上下文是一个进程在某一时刻的执行状态,包括:

  • 程序执行到了哪里(程序计数器);
  • 正在使用哪些数据(寄存器的值);
  • 栈的情况(栈指针、栈内容);
  • 内存映射(页表基址);
  • 打开的文件(文件描述符表);
  • 信号处理状态等。

简单来说,上下文就是进程当前运行状态的全部信息。有了这些信息,进程就可以在任意时刻被暂停,并在稍后被恢复,就像从未被中断过一样。

1.2 上下文切换的定义

给出一个正式的定义:

上下文切换(Context Switch)是操作系统在多任务环境中,把 CPU 从一个进程(或线程)切换到另一个进程(或线程)时,保存当前进程的上下文、恢复下一个进程的上下文的过程。

这个定义里有三个关键点:

  1. 保存当前进程的上下文:把当前进程的执行状态存储起来;
  2. 恢复下一个进程的上下文:把下一个进程之前保存的执行状态加载回来;
  3. 切换 CPU 的执行流:CPU 从执行一个进程变为执行另一个进程。

1.3 上下文切换在系统中的位置

#mermaid-svg-civqToQbGV1ZM5L6{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-civqToQbGV1ZM5L6 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-civqToQbGV1ZM5L6 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-civqToQbGV1ZM5L6 .error-icon{fill:#552222;}#mermaid-svg-civqToQbGV1ZM5L6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-civqToQbGV1ZM5L6 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-civqToQbGV1ZM5L6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-civqToQbGV1ZM5L6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-civqToQbGV1ZM5L6 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-civqToQbGV1ZM5L6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-civqToQbGV1ZM5L6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-civqToQbGV1ZM5L6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-civqToQbGV1ZM5L6 .marker.cross{stroke:#333333;}#mermaid-svg-civqToQbGV1ZM5L6 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-civqToQbGV1ZM5L6 p{margin:0;}#mermaid-svg-civqToQbGV1ZM5L6 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-civqToQbGV1ZM5L6 .cluster-label text{fill:#333;}#mermaid-svg-civqToQbGV1ZM5L6 .cluster-label span{color:#333;}#mermaid-svg-civqToQbGV1ZM5L6 .cluster-label span p{background-color:transparent;}#mermaid-svg-civqToQbGV1ZM5L6 .label text,#mermaid-svg-civqToQbGV1ZM5L6 span{fill:#333;color:#333;}#mermaid-svg-civqToQbGV1ZM5L6 .node rect,#mermaid-svg-civqToQbGV1ZM5L6 .node circle,#mermaid-svg-civqToQbGV1ZM5L6 .node ellipse,#mermaid-svg-civqToQbGV1ZM5L6 .node polygon,#mermaid-svg-civqToQbGV1ZM5L6 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-civqToQbGV1ZM5L6 .rough-node .label text,#mermaid-svg-civqToQbGV1ZM5L6 .node .label text,#mermaid-svg-civqToQbGV1ZM5L6 .image-shape .label,#mermaid-svg-civqToQbGV1ZM5L6 .icon-shape .label{text-anchor:middle;}#mermaid-svg-civqToQbGV1ZM5L6 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-civqToQbGV1ZM5L6 .rough-node .label,#mermaid-svg-civqToQbGV1ZM5L6 .node .label,#mermaid-svg-civqToQbGV1ZM5L6 .image-shape .label,#mermaid-svg-civqToQbGV1ZM5L6 .icon-shape .label{text-align:center;}#mermaid-svg-civqToQbGV1ZM5L6 .node.clickable{cursor:pointer;}#mermaid-svg-civqToQbGV1ZM5L6 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-civqToQbGV1ZM5L6 .arrowheadPath{fill:#333333;}#mermaid-svg-civqToQbGV1ZM5L6 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-civqToQbGV1ZM5L6 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-civqToQbGV1ZM5L6 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-civqToQbGV1ZM5L6 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-civqToQbGV1ZM5L6 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-civqToQbGV1ZM5L6 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-civqToQbGV1ZM5L6 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-civqToQbGV1ZM5L6 .cluster text{fill:#333;}#mermaid-svg-civqToQbGV1ZM5L6 .cluster span{color:#333;}#mermaid-svg-civqToQbGV1ZM5L6 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-civqToQbGV1ZM5L6 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-civqToQbGV1ZM5L6 rect.text{fill:none;stroke-width:0;}#mermaid-svg-civqToQbGV1ZM5L6 .icon-shape,#mermaid-svg-civqToQbGV1ZM5L6 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-civqToQbGV1ZM5L6 .icon-shape p,#mermaid-svg-civqToQbGV1ZM5L6 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-civqToQbGV1ZM5L6 .icon-shape .label rect,#mermaid-svg-civqToQbGV1ZM5L6 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-civqToQbGV1ZM5L6 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-civqToQbGV1ZM5L6 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-civqToQbGV1ZM5L6 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 进程B
内核
进程A
执行中
被中断
保存进程A的上下文
选择进程B
恢复进程B的上下文
被恢复
继续执行

图 1:上下文切换在系统中的位置。 内核负责保存和恢复上下文,调度器负责选择下一个进程。

从图 1 可以看出,上下文切换发生在内核中。进程本身并不知道自己被切换了,它只知道自己被暂停了一下,然后继续执行。

二、上下文切换时到底保存了什么?

这是本文的核心问题。上下文切换时,操作系统需要保存哪些信息?

2.1 CPU 寄存器

CPU 寄存器是进程执行时最核心的状态。包括:

寄存器类型 作用
通用寄存器 存储临时数据、函数参数、返回值
程序计数器(PC) 下一条要执行的指令地址
栈指针(SP) 当前栈顶的位置
基址指针(BP) 当前栈帧的基址
程序状态字(PSW) 标志位、特权级、中断使能等

这些寄存器的值决定了进程执行到哪里、正在处理什么数据。保存了这些寄存器,就等于保存了进程的"执行现场"。

2.2 程序计数器(PC)

程序计数器(Program Counter,PC)是最关键的寄存器之一。它存储着下一条要执行的指令的地址。

当进程被中断时,PC 指向的是下一条尚未执行的指令。恢复时,CPU 从 PC 指向的地址继续执行,就好像从未被中断过。
#mermaid-svg-auHuOot5Tq6UwLzu{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-auHuOot5Tq6UwLzu .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-auHuOot5Tq6UwLzu .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-auHuOot5Tq6UwLzu .error-icon{fill:#552222;}#mermaid-svg-auHuOot5Tq6UwLzu .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-auHuOot5Tq6UwLzu .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-auHuOot5Tq6UwLzu .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-auHuOot5Tq6UwLzu .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-auHuOot5Tq6UwLzu .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-auHuOot5Tq6UwLzu .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-auHuOot5Tq6UwLzu .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-auHuOot5Tq6UwLzu .marker{fill:#333333;stroke:#333333;}#mermaid-svg-auHuOot5Tq6UwLzu .marker.cross{stroke:#333333;}#mermaid-svg-auHuOot5Tq6UwLzu svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-auHuOot5Tq6UwLzu p{margin:0;}#mermaid-svg-auHuOot5Tq6UwLzu .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-auHuOot5Tq6UwLzu .cluster-label text{fill:#333;}#mermaid-svg-auHuOot5Tq6UwLzu .cluster-label span{color:#333;}#mermaid-svg-auHuOot5Tq6UwLzu .cluster-label span p{background-color:transparent;}#mermaid-svg-auHuOot5Tq6UwLzu .label text,#mermaid-svg-auHuOot5Tq6UwLzu span{fill:#333;color:#333;}#mermaid-svg-auHuOot5Tq6UwLzu .node rect,#mermaid-svg-auHuOot5Tq6UwLzu .node circle,#mermaid-svg-auHuOot5Tq6UwLzu .node ellipse,#mermaid-svg-auHuOot5Tq6UwLzu .node polygon,#mermaid-svg-auHuOot5Tq6UwLzu .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-auHuOot5Tq6UwLzu .rough-node .label text,#mermaid-svg-auHuOot5Tq6UwLzu .node .label text,#mermaid-svg-auHuOot5Tq6UwLzu .image-shape .label,#mermaid-svg-auHuOot5Tq6UwLzu .icon-shape .label{text-anchor:middle;}#mermaid-svg-auHuOot5Tq6UwLzu .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-auHuOot5Tq6UwLzu .rough-node .label,#mermaid-svg-auHuOot5Tq6UwLzu .node .label,#mermaid-svg-auHuOot5Tq6UwLzu .image-shape .label,#mermaid-svg-auHuOot5Tq6UwLzu .icon-shape .label{text-align:center;}#mermaid-svg-auHuOot5Tq6UwLzu .node.clickable{cursor:pointer;}#mermaid-svg-auHuOot5Tq6UwLzu .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-auHuOot5Tq6UwLzu .arrowheadPath{fill:#333333;}#mermaid-svg-auHuOot5Tq6UwLzu .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-auHuOot5Tq6UwLzu .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-auHuOot5Tq6UwLzu .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-auHuOot5Tq6UwLzu .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-auHuOot5Tq6UwLzu .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-auHuOot5Tq6UwLzu .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-auHuOot5Tq6UwLzu .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-auHuOot5Tq6UwLzu .cluster text{fill:#333;}#mermaid-svg-auHuOot5Tq6UwLzu .cluster span{color:#333;}#mermaid-svg-auHuOot5Tq6UwLzu div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-auHuOot5Tq6UwLzu .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-auHuOot5Tq6UwLzu rect.text{fill:none;stroke-width:0;}#mermaid-svg-auHuOot5Tq6UwLzu .icon-shape,#mermaid-svg-auHuOot5Tq6UwLzu .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-auHuOot5Tq6UwLzu .icon-shape p,#mermaid-svg-auHuOot5Tq6UwLzu .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-auHuOot5Tq6UwLzu .icon-shape .label rect,#mermaid-svg-auHuOot5Tq6UwLzu .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-auHuOot5Tq6UwLzu .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-auHuOot5Tq6UwLzu .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-auHuOot5Tq6UwLzu :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 指令 1
指令 2
指令 3
指令 4

被中断
下一条指令

PC 指向这里

图 2:程序计数器的作用。 进程被中断时,PC 指向下一条未执行的指令。

2.3 栈指针(SP)

栈是进程存放局部变量、函数参数、返回地址的地方。栈指针(Stack Pointer,SP)指向当前栈顶。

当进程被中断时,栈中可能有多层函数调用的信息。保存 SP,就能在恢复时找到正确的栈位置。

2.4 内存管理信息

进程的内存管理信息也需要保存,包括:

  • 页表基址:指向该进程的页表;
  • 内存限制:代码段、数据段、堆、栈的边界。

在切换进程时,操作系统需要切换页表,让 CPU 使用新进程的地址空间。这也是上下文切换开销大的一个重要原因。

2.5 其他状态

除了上述核心状态,还需要保存:

状态 说明
文件描述符表 进程打开的文件
信号处理状态 信号处理函数的地址
进程状态 就绪、运行、阻塞
调度信息 优先级、时间片剩余

2.6 保存到哪里?

这些上下文信息保存在哪里?答案是进程控制块(PCB)。

每个进程有一个 PCB,操作系统在切换进程时,把当前进程的上下文保存到它的 PCB 中,然后从下一个进程的 PCB 中恢复上下文。
#mermaid-svg-nZCo6Kyx7WEtkJ63{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-nZCo6Kyx7WEtkJ63 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .error-icon{fill:#552222;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .marker.cross{stroke:#333333;}#mermaid-svg-nZCo6Kyx7WEtkJ63 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-nZCo6Kyx7WEtkJ63 p{margin:0;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .cluster-label text{fill:#333;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .cluster-label span{color:#333;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .cluster-label span p{background-color:transparent;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .label text,#mermaid-svg-nZCo6Kyx7WEtkJ63 span{fill:#333;color:#333;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .node rect,#mermaid-svg-nZCo6Kyx7WEtkJ63 .node circle,#mermaid-svg-nZCo6Kyx7WEtkJ63 .node ellipse,#mermaid-svg-nZCo6Kyx7WEtkJ63 .node polygon,#mermaid-svg-nZCo6Kyx7WEtkJ63 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .rough-node .label text,#mermaid-svg-nZCo6Kyx7WEtkJ63 .node .label text,#mermaid-svg-nZCo6Kyx7WEtkJ63 .image-shape .label,#mermaid-svg-nZCo6Kyx7WEtkJ63 .icon-shape .label{text-anchor:middle;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .rough-node .label,#mermaid-svg-nZCo6Kyx7WEtkJ63 .node .label,#mermaid-svg-nZCo6Kyx7WEtkJ63 .image-shape .label,#mermaid-svg-nZCo6Kyx7WEtkJ63 .icon-shape .label{text-align:center;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .node.clickable{cursor:pointer;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .arrowheadPath{fill:#333333;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-nZCo6Kyx7WEtkJ63 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nZCo6Kyx7WEtkJ63 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-nZCo6Kyx7WEtkJ63 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .cluster text{fill:#333;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .cluster span{color:#333;}#mermaid-svg-nZCo6Kyx7WEtkJ63 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-nZCo6Kyx7WEtkJ63 rect.text{fill:none;stroke-width:0;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .icon-shape,#mermaid-svg-nZCo6Kyx7WEtkJ63 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .icon-shape p,#mermaid-svg-nZCo6Kyx7WEtkJ63 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .icon-shape .label rect,#mermaid-svg-nZCo6Kyx7WEtkJ63 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-nZCo6Kyx7WEtkJ63 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-nZCo6Kyx7WEtkJ63 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-nZCo6Kyx7WEtkJ63 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 进程B的PCB
进程A的PCB
保存
恢复
寄存器值
程序计数器
栈指针
页表基址
寄存器值
程序计数器
栈指针
页表基址
内核

图 3:上下文保存在 PCB 中。 切换时,从当前进程的 PCB 保存,从下一个进程的 PCB 恢复。

三、上下文切换的类型

上下文切换并不是只有一种。根据切换的对象不同,可以分为几种类型。

3.1 进程上下文切换

进程上下文切换是最完整、开销最大的切换。它不仅需要保存和恢复 CPU 寄存器,还需要切换页表、刷新 TLB、切换内存地址空间。

进程上下文切换的开销包括:

  • 保存和恢复寄存器;
  • 切换页表;
  • 刷新 TLB;
  • 刷新 CPU 缓存(部分架构)。

3.2 线程上下文切换

线程上下文切换发生在同一进程内的两个线程之间。由于同一进程的线程共享地址空间,线程切换不需要切换页表,也不需要刷新 TLB,因此开销比进程切换小得多。

对比项 进程切换 线程切换
保存寄存器 需要 需要
切换页表 需要 不需要
刷新 TLB 需要 不需要
开销 大 小

#mermaid-svg-CiLcdDII5YWpjAc4{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-CiLcdDII5YWpjAc4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-CiLcdDII5YWpjAc4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-CiLcdDII5YWpjAc4 .error-icon{fill:#552222;}#mermaid-svg-CiLcdDII5YWpjAc4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-CiLcdDII5YWpjAc4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-CiLcdDII5YWpjAc4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-CiLcdDII5YWpjAc4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-CiLcdDII5YWpjAc4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-CiLcdDII5YWpjAc4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-CiLcdDII5YWpjAc4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-CiLcdDII5YWpjAc4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-CiLcdDII5YWpjAc4 .marker.cross{stroke:#333333;}#mermaid-svg-CiLcdDII5YWpjAc4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-CiLcdDII5YWpjAc4 p{margin:0;}#mermaid-svg-CiLcdDII5YWpjAc4 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-CiLcdDII5YWpjAc4 .cluster-label text{fill:#333;}#mermaid-svg-CiLcdDII5YWpjAc4 .cluster-label span{color:#333;}#mermaid-svg-CiLcdDII5YWpjAc4 .cluster-label span p{background-color:transparent;}#mermaid-svg-CiLcdDII5YWpjAc4 .label text,#mermaid-svg-CiLcdDII5YWpjAc4 span{fill:#333;color:#333;}#mermaid-svg-CiLcdDII5YWpjAc4 .node rect,#mermaid-svg-CiLcdDII5YWpjAc4 .node circle,#mermaid-svg-CiLcdDII5YWpjAc4 .node ellipse,#mermaid-svg-CiLcdDII5YWpjAc4 .node polygon,#mermaid-svg-CiLcdDII5YWpjAc4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-CiLcdDII5YWpjAc4 .rough-node .label text,#mermaid-svg-CiLcdDII5YWpjAc4 .node .label text,#mermaid-svg-CiLcdDII5YWpjAc4 .image-shape .label,#mermaid-svg-CiLcdDII5YWpjAc4 .icon-shape .label{text-anchor:middle;}#mermaid-svg-CiLcdDII5YWpjAc4 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-CiLcdDII5YWpjAc4 .rough-node .label,#mermaid-svg-CiLcdDII5YWpjAc4 .node .label,#mermaid-svg-CiLcdDII5YWpjAc4 .image-shape .label,#mermaid-svg-CiLcdDII5YWpjAc4 .icon-shape .label{text-align:center;}#mermaid-svg-CiLcdDII5YWpjAc4 .node.clickable{cursor:pointer;}#mermaid-svg-CiLcdDII5YWpjAc4 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-CiLcdDII5YWpjAc4 .arrowheadPath{fill:#333333;}#mermaid-svg-CiLcdDII5YWpjAc4 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-CiLcdDII5YWpjAc4 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-CiLcdDII5YWpjAc4 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CiLcdDII5YWpjAc4 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-CiLcdDII5YWpjAc4 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CiLcdDII5YWpjAc4 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-CiLcdDII5YWpjAc4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-CiLcdDII5YWpjAc4 .cluster text{fill:#333;}#mermaid-svg-CiLcdDII5YWpjAc4 .cluster span{color:#333;}#mermaid-svg-CiLcdDII5YWpjAc4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-CiLcdDII5YWpjAc4 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-CiLcdDII5YWpjAc4 rect.text{fill:none;stroke-width:0;}#mermaid-svg-CiLcdDII5YWpjAc4 .icon-shape,#mermaid-svg-CiLcdDII5YWpjAc4 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-CiLcdDII5YWpjAc4 .icon-shape p,#mermaid-svg-CiLcdDII5YWpjAc4 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-CiLcdDII5YWpjAc4 .icon-shape .label rect,#mermaid-svg-CiLcdDII5YWpjAc4 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-CiLcdDII5YWpjAc4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-CiLcdDII5YWpjAc4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-CiLcdDII5YWpjAc4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 线程切换
保存寄存器
恢复寄存器
进程切换
保存寄存器
切换页表
刷新 TLB
恢复寄存器

图 4:进程切换与线程切换的对比。 进程切换需要切换页表和刷新 TLB,线程切换不需要。

3.3 中断上下文切换

中断上下文切换发生在中断处理时。CPU 从用户态切换到内核态,保存用户程序的上下文,执行中断处理程序,然后恢复。

中断上下文切换和进程上下文切换的区别:

  • 中断上下文切换不涉及进程切换,只是从用户态到内核态的切换;
  • 中断处理程序运行在内核态,使用内核栈;
  • 中断处理完毕后,可能返回原进程,也可能触发调度。

3.4 模式切换

模式切换(Mode Switch)是指 CPU 从用户态切换到内核态,或从内核态切换到用户态。系统调用、中断、异常都会触发模式切换。

模式切换和上下文切换的区别:

对比项 模式切换 上下文切换
是否切换进程 不一定 一定
是否保存全部上下文 不一定 一定
开销 较小 较大
触发方式 系统调用、中断、异常 调度器决定

注意:模式切换不一定导致上下文切换。例如,系统调用进入内核后,如果不需要切换进程,处理完直接返回原进程,就没有发生上下文切换。
#mermaid-svg-klBWQxE7jihYm79l{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-klBWQxE7jihYm79l .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-klBWQxE7jihYm79l .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-klBWQxE7jihYm79l .error-icon{fill:#552222;}#mermaid-svg-klBWQxE7jihYm79l .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-klBWQxE7jihYm79l .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-klBWQxE7jihYm79l .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-klBWQxE7jihYm79l .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-klBWQxE7jihYm79l .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-klBWQxE7jihYm79l .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-klBWQxE7jihYm79l .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-klBWQxE7jihYm79l .marker{fill:#333333;stroke:#333333;}#mermaid-svg-klBWQxE7jihYm79l .marker.cross{stroke:#333333;}#mermaid-svg-klBWQxE7jihYm79l svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-klBWQxE7jihYm79l p{margin:0;}#mermaid-svg-klBWQxE7jihYm79l .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-klBWQxE7jihYm79l .cluster-label text{fill:#333;}#mermaid-svg-klBWQxE7jihYm79l .cluster-label span{color:#333;}#mermaid-svg-klBWQxE7jihYm79l .cluster-label span p{background-color:transparent;}#mermaid-svg-klBWQxE7jihYm79l .label text,#mermaid-svg-klBWQxE7jihYm79l span{fill:#333;color:#333;}#mermaid-svg-klBWQxE7jihYm79l .node rect,#mermaid-svg-klBWQxE7jihYm79l .node circle,#mermaid-svg-klBWQxE7jihYm79l .node ellipse,#mermaid-svg-klBWQxE7jihYm79l .node polygon,#mermaid-svg-klBWQxE7jihYm79l .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-klBWQxE7jihYm79l .rough-node .label text,#mermaid-svg-klBWQxE7jihYm79l .node .label text,#mermaid-svg-klBWQxE7jihYm79l .image-shape .label,#mermaid-svg-klBWQxE7jihYm79l .icon-shape .label{text-anchor:middle;}#mermaid-svg-klBWQxE7jihYm79l .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-klBWQxE7jihYm79l .rough-node .label,#mermaid-svg-klBWQxE7jihYm79l .node .label,#mermaid-svg-klBWQxE7jihYm79l .image-shape .label,#mermaid-svg-klBWQxE7jihYm79l .icon-shape .label{text-align:center;}#mermaid-svg-klBWQxE7jihYm79l .node.clickable{cursor:pointer;}#mermaid-svg-klBWQxE7jihYm79l .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-klBWQxE7jihYm79l .arrowheadPath{fill:#333333;}#mermaid-svg-klBWQxE7jihYm79l .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-klBWQxE7jihYm79l .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-klBWQxE7jihYm79l .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-klBWQxE7jihYm79l .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-klBWQxE7jihYm79l .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-klBWQxE7jihYm79l .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-klBWQxE7jihYm79l .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-klBWQxE7jihYm79l .cluster text{fill:#333;}#mermaid-svg-klBWQxE7jihYm79l .cluster span{color:#333;}#mermaid-svg-klBWQxE7jihYm79l div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-klBWQxE7jihYm79l .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-klBWQxE7jihYm79l rect.text{fill:none;stroke-width:0;}#mermaid-svg-klBWQxE7jihYm79l .icon-shape,#mermaid-svg-klBWQxE7jihYm79l .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-klBWQxE7jihYm79l .icon-shape p,#mermaid-svg-klBWQxE7jihYm79l .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-klBWQxE7jihYm79l .icon-shape .label rect,#mermaid-svg-klBWQxE7jihYm79l .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-klBWQxE7jihYm79l .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-klBWQxE7jihYm79l .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-klBWQxE7jihYm79l :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 系统调用
处理完毕, 返回原进程
需要调度
用户态
内核态
保存上下文
选择新进程
恢复上下文

图 5:模式切换与上下文切换的关系。 系统调用进入内核后,可能只发生模式切换,也可能触发上下文切换。

四、上下文切换的完整流程

上下文切换是一个复杂的过程,涉及硬件和操作系统的紧密配合。

4.1 完整流程图

进程B PCB_B PCB_A 内核 CPU 进程A 进程B PCB_B PCB_A 内核 CPU 进程A #mermaid-svg-OmAjFcUHoG0tOSwy{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-OmAjFcUHoG0tOSwy .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-OmAjFcUHoG0tOSwy .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-OmAjFcUHoG0tOSwy .error-icon{fill:#552222;}#mermaid-svg-OmAjFcUHoG0tOSwy .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-OmAjFcUHoG0tOSwy .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-OmAjFcUHoG0tOSwy .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-OmAjFcUHoG0tOSwy .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-OmAjFcUHoG0tOSwy .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-OmAjFcUHoG0tOSwy .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-OmAjFcUHoG0tOSwy .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-OmAjFcUHoG0tOSwy .marker{fill:#333333;stroke:#333333;}#mermaid-svg-OmAjFcUHoG0tOSwy .marker.cross{stroke:#333333;}#mermaid-svg-OmAjFcUHoG0tOSwy svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-OmAjFcUHoG0tOSwy p{margin:0;}#mermaid-svg-OmAjFcUHoG0tOSwy .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-OmAjFcUHoG0tOSwy text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-OmAjFcUHoG0tOSwy .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-OmAjFcUHoG0tOSwy .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-OmAjFcUHoG0tOSwy .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-OmAjFcUHoG0tOSwy .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-OmAjFcUHoG0tOSwy #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-OmAjFcUHoG0tOSwy .sequenceNumber{fill:white;}#mermaid-svg-OmAjFcUHoG0tOSwy #sequencenumber{fill:#333;}#mermaid-svg-OmAjFcUHoG0tOSwy #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-OmAjFcUHoG0tOSwy .messageText{fill:#333;stroke:none;}#mermaid-svg-OmAjFcUHoG0tOSwy .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-OmAjFcUHoG0tOSwy .labelText,#mermaid-svg-OmAjFcUHoG0tOSwy .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-OmAjFcUHoG0tOSwy .loopText,#mermaid-svg-OmAjFcUHoG0tOSwy .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-OmAjFcUHoG0tOSwy .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-OmAjFcUHoG0tOSwy .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-OmAjFcUHoG0tOSwy .noteText,#mermaid-svg-OmAjFcUHoG0tOSwy .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-OmAjFcUHoG0tOSwy .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-OmAjFcUHoG0tOSwy .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-OmAjFcUHoG0tOSwy .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-OmAjFcUHoG0tOSwy .actorPopupMenu{position:absolute;}#mermaid-svg-OmAjFcUHoG0tOSwy .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-OmAjFcUHoG0tOSwy .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-OmAjFcUHoG0tOSwy .actor-man circle,#mermaid-svg-OmAjFcUHoG0tOSwy line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-OmAjFcUHoG0tOSwy :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 正在执行触发调度(时间片用完/阻塞)保存进程A的寄存器保存程序计数器保存栈指针保存页表基址选择进程B读取进程B的上下文恢复进程B的寄存器恢复进程B的程序计数器切换页表到进程B刷新 TLB从上次中断处继续执行

图 6:上下文切换的完整流程。 从触发调度到恢复新进程,经历保存、选择、恢复三个阶段。

4.2 详细步骤

  1. 触发调度:时间片用完、进程阻塞、更高优先级进程就绪等;
  2. 进入内核态:CPU 从用户态切换到内核态;
  3. 保存进程 A 的上下文:把寄存器、PC、SP、页表基址等保存到 PCB_A;
  4. 选择进程 B:调度器从就绪队列中选择下一个进程;
  5. 恢复进程 B 的上下文:从 PCB_B 中读取寄存器、PC、SP 等;
  6. 切换页表:把 CPU 的页表基址寄存器指向进程 B 的页表;
  7. 刷新 TLB:使旧的 TLB 条目失效(或使用 ASID 避免刷新);
  8. 返回用户态:CPU 从内核态切换回用户态;
  9. 继续执行进程 B:从进程 B 上次中断的地方继续执行。

4.3 一个具体的例子

假设进程 A 正在执行,时间片用完,操作系统切换到进程 B。

进程 A 的上下文:

  • PC = 0x00401000(下一条指令地址);
  • SP = 0x7FFF0000(栈顶);
  • 通用寄存器:RAX = 10, RBX = 20, RCX = 30;
  • 页表基址 = 0x1000。

进程 B 的上下文:

  • PC = 0x00402000;
  • SP = 0x7FFE0000;
  • 通用寄存器:RAX = 100, RBX = 200, RCX = 300;
  • 页表基址 = 0x2000。

切换过程:

  1. 保存 A 的 PC、SP、寄存器到 PCB_A;
  2. 从 PCB_B 读取 B 的 PC、SP、寄存器;
  3. 把 CPU 的页表基址寄存器改为 0x2000;
  4. 刷新 TLB;
  5. CPU 从 0x00402000 继续执行进程 B。

#mermaid-svg-9Iyush5zKqOPVb2R{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-9Iyush5zKqOPVb2R .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-9Iyush5zKqOPVb2R .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-9Iyush5zKqOPVb2R .error-icon{fill:#552222;}#mermaid-svg-9Iyush5zKqOPVb2R .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-9Iyush5zKqOPVb2R .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-9Iyush5zKqOPVb2R .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-9Iyush5zKqOPVb2R .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-9Iyush5zKqOPVb2R .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-9Iyush5zKqOPVb2R .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-9Iyush5zKqOPVb2R .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-9Iyush5zKqOPVb2R .marker{fill:#333333;stroke:#333333;}#mermaid-svg-9Iyush5zKqOPVb2R .marker.cross{stroke:#333333;}#mermaid-svg-9Iyush5zKqOPVb2R svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-9Iyush5zKqOPVb2R p{margin:0;}#mermaid-svg-9Iyush5zKqOPVb2R .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-9Iyush5zKqOPVb2R .cluster-label text{fill:#333;}#mermaid-svg-9Iyush5zKqOPVb2R .cluster-label span{color:#333;}#mermaid-svg-9Iyush5zKqOPVb2R .cluster-label span p{background-color:transparent;}#mermaid-svg-9Iyush5zKqOPVb2R .label text,#mermaid-svg-9Iyush5zKqOPVb2R span{fill:#333;color:#333;}#mermaid-svg-9Iyush5zKqOPVb2R .node rect,#mermaid-svg-9Iyush5zKqOPVb2R .node circle,#mermaid-svg-9Iyush5zKqOPVb2R .node ellipse,#mermaid-svg-9Iyush5zKqOPVb2R .node polygon,#mermaid-svg-9Iyush5zKqOPVb2R .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-9Iyush5zKqOPVb2R .rough-node .label text,#mermaid-svg-9Iyush5zKqOPVb2R .node .label text,#mermaid-svg-9Iyush5zKqOPVb2R .image-shape .label,#mermaid-svg-9Iyush5zKqOPVb2R .icon-shape .label{text-anchor:middle;}#mermaid-svg-9Iyush5zKqOPVb2R .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-9Iyush5zKqOPVb2R .rough-node .label,#mermaid-svg-9Iyush5zKqOPVb2R .node .label,#mermaid-svg-9Iyush5zKqOPVb2R .image-shape .label,#mermaid-svg-9Iyush5zKqOPVb2R .icon-shape .label{text-align:center;}#mermaid-svg-9Iyush5zKqOPVb2R .node.clickable{cursor:pointer;}#mermaid-svg-9Iyush5zKqOPVb2R .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-9Iyush5zKqOPVb2R .arrowheadPath{fill:#333333;}#mermaid-svg-9Iyush5zKqOPVb2R .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-9Iyush5zKqOPVb2R .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-9Iyush5zKqOPVb2R .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-9Iyush5zKqOPVb2R .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-9Iyush5zKqOPVb2R .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-9Iyush5zKqOPVb2R .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-9Iyush5zKqOPVb2R .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-9Iyush5zKqOPVb2R .cluster text{fill:#333;}#mermaid-svg-9Iyush5zKqOPVb2R .cluster span{color:#333;}#mermaid-svg-9Iyush5zKqOPVb2R div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-9Iyush5zKqOPVb2R .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-9Iyush5zKqOPVb2R rect.text{fill:none;stroke-width:0;}#mermaid-svg-9Iyush5zKqOPVb2R .icon-shape,#mermaid-svg-9Iyush5zKqOPVb2R .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-9Iyush5zKqOPVb2R .icon-shape p,#mermaid-svg-9Iyush5zKqOPVb2R .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-9Iyush5zKqOPVb2R .icon-shape .label rect,#mermaid-svg-9Iyush5zKqOPVb2R .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-9Iyush5zKqOPVb2R .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-9Iyush5zKqOPVb2R .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-9Iyush5zKqOPVb2R :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 进程B
进程A
保存
恢复
PC=0x401000
SP=0x7FFF0000
页表=0x1000
PC=0x402000
SP=0x7FFE0000
页表=0x2000
内核

图 7:上下文切换的具体例子。 从进程 A 的上下文切换到进程 B 的上下文。

五、上下文切换的开销

上下文切换不是免费的。它的开销来自多个方面。

5.1 直接开销

直接开销是上下文切换本身消耗的时间:

开销来源 说明
保存寄存器 把寄存器写入 PCB
恢复寄存器 从 PCB 读取寄存器
切换页表 修改页表基址寄存器
刷新 TLB 使旧 TLB 条目失效
内核代码执行 调度器选择进程

5.2 间接开销

间接开销是上下文切换对系统性能的间接影响:

开销来源 说明
CPU 缓存失效 新进程的代码和数据可能不在缓存中
TLB 失效 地址转换需要重新查询页表
分支预测失效 CPU 的分支预测器需要重新学习
流水线冲刷 CPU 流水线被清空

#mermaid-svg-uUy1nGm5qaN7NBqd{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-uUy1nGm5qaN7NBqd .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-uUy1nGm5qaN7NBqd .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-uUy1nGm5qaN7NBqd .error-icon{fill:#552222;}#mermaid-svg-uUy1nGm5qaN7NBqd .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-uUy1nGm5qaN7NBqd .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-uUy1nGm5qaN7NBqd .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-uUy1nGm5qaN7NBqd .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-uUy1nGm5qaN7NBqd .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-uUy1nGm5qaN7NBqd .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-uUy1nGm5qaN7NBqd .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-uUy1nGm5qaN7NBqd .marker{fill:#333333;stroke:#333333;}#mermaid-svg-uUy1nGm5qaN7NBqd .marker.cross{stroke:#333333;}#mermaid-svg-uUy1nGm5qaN7NBqd svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-uUy1nGm5qaN7NBqd p{margin:0;}#mermaid-svg-uUy1nGm5qaN7NBqd .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-uUy1nGm5qaN7NBqd .cluster-label text{fill:#333;}#mermaid-svg-uUy1nGm5qaN7NBqd .cluster-label span{color:#333;}#mermaid-svg-uUy1nGm5qaN7NBqd .cluster-label span p{background-color:transparent;}#mermaid-svg-uUy1nGm5qaN7NBqd .label text,#mermaid-svg-uUy1nGm5qaN7NBqd span{fill:#333;color:#333;}#mermaid-svg-uUy1nGm5qaN7NBqd .node rect,#mermaid-svg-uUy1nGm5qaN7NBqd .node circle,#mermaid-svg-uUy1nGm5qaN7NBqd .node ellipse,#mermaid-svg-uUy1nGm5qaN7NBqd .node polygon,#mermaid-svg-uUy1nGm5qaN7NBqd .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-uUy1nGm5qaN7NBqd .rough-node .label text,#mermaid-svg-uUy1nGm5qaN7NBqd .node .label text,#mermaid-svg-uUy1nGm5qaN7NBqd .image-shape .label,#mermaid-svg-uUy1nGm5qaN7NBqd .icon-shape .label{text-anchor:middle;}#mermaid-svg-uUy1nGm5qaN7NBqd .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-uUy1nGm5qaN7NBqd .rough-node .label,#mermaid-svg-uUy1nGm5qaN7NBqd .node .label,#mermaid-svg-uUy1nGm5qaN7NBqd .image-shape .label,#mermaid-svg-uUy1nGm5qaN7NBqd .icon-shape .label{text-align:center;}#mermaid-svg-uUy1nGm5qaN7NBqd .node.clickable{cursor:pointer;}#mermaid-svg-uUy1nGm5qaN7NBqd .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-uUy1nGm5qaN7NBqd .arrowheadPath{fill:#333333;}#mermaid-svg-uUy1nGm5qaN7NBqd .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-uUy1nGm5qaN7NBqd .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-uUy1nGm5qaN7NBqd .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-uUy1nGm5qaN7NBqd .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-uUy1nGm5qaN7NBqd .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-uUy1nGm5qaN7NBqd .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-uUy1nGm5qaN7NBqd .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-uUy1nGm5qaN7NBqd .cluster text{fill:#333;}#mermaid-svg-uUy1nGm5qaN7NBqd .cluster span{color:#333;}#mermaid-svg-uUy1nGm5qaN7NBqd div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-uUy1nGm5qaN7NBqd .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-uUy1nGm5qaN7NBqd rect.text{fill:none;stroke-width:0;}#mermaid-svg-uUy1nGm5qaN7NBqd .icon-shape,#mermaid-svg-uUy1nGm5qaN7NBqd .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-uUy1nGm5qaN7NBqd .icon-shape p,#mermaid-svg-uUy1nGm5qaN7NBqd .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-uUy1nGm5qaN7NBqd .icon-shape .label rect,#mermaid-svg-uUy1nGm5qaN7NBqd .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-uUy1nGm5qaN7NBqd .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-uUy1nGm5qaN7NBqd .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-uUy1nGm5qaN7NBqd :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 上下文切换开销
直接开销
间接开销
保存/恢复寄存器
切换页表
刷新 TLB
CPU 缓存失效
TLB 失效
分支预测失效

图 8:上下文切换的开销来源。 直接开销和间接开销共同影响性能。

5.3 开销有多大?

上下文切换的开销因硬件和操作系统而异,通常在 几微秒 左右。听起来不多,但如果系统每秒切换上千次,累积起来就很可观。

假设一次上下文切换需要 5 微秒,每秒切换 1000 次,那么每秒有 5 毫秒花在切换上,占 CPU 时间的 0.5%。如果每秒切换 10000 次,就有 5% 的 CPU 时间花在切换上。

5.4 如何测量上下文切换次数?

在 Linux 中,可以使用以下命令查看上下文切换次数:

bash 复制代码
# 查看系统整体的上下文切换统计
vmstat 1

# 查看特定进程的上下文切换
pidstat -w -p PID 1

vmstat 输出中的 cs 列表示每秒上下文切换次数。pidstat 可以查看特定进程的自愿和非自愿上下文切换。

六、上下文切换的触发时机

上下文切换不是随时发生的,而是在特定时机触发。

6.1 触发时机

触发时机 说明 是否自愿
时间片用完 分时系统中,进程用完时间片 非自愿
进程阻塞 进程请求 I/O 或等待事件 自愿
进程终止 进程执行完毕 自愿
更高优先级进程就绪 抢占式调度 非自愿
系统调用 进程主动让出 CPU 自愿
中断处理 中断处理完后可能触发调度 非自愿

6.2 自愿切换与非自愿切换

自愿上下文切换 (Voluntary Context Switch):进程主动放弃 CPU,如等待 I/O、调用 sleep()、等待锁。

非自愿上下文切换(Involuntary Context Switch):进程被迫放弃 CPU,如时间片用完、被更高优先级进程抢占。

在 Linux 中,可以用 pidstat -w 查看这两种切换:

bash 复制代码
pidstat -w -p PID 1

输出中的 cswch/s 是自愿切换,nvcswch/s 是非自愿切换。
#mermaid-svg-cKUlSGERzv5OFidy{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-cKUlSGERzv5OFidy .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-cKUlSGERzv5OFidy .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-cKUlSGERzv5OFidy .error-icon{fill:#552222;}#mermaid-svg-cKUlSGERzv5OFidy .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-cKUlSGERzv5OFidy .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-cKUlSGERzv5OFidy .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-cKUlSGERzv5OFidy .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-cKUlSGERzv5OFidy .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-cKUlSGERzv5OFidy .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-cKUlSGERzv5OFidy .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-cKUlSGERzv5OFidy .marker{fill:#333333;stroke:#333333;}#mermaid-svg-cKUlSGERzv5OFidy .marker.cross{stroke:#333333;}#mermaid-svg-cKUlSGERzv5OFidy svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-cKUlSGERzv5OFidy p{margin:0;}#mermaid-svg-cKUlSGERzv5OFidy .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-cKUlSGERzv5OFidy .cluster-label text{fill:#333;}#mermaid-svg-cKUlSGERzv5OFidy .cluster-label span{color:#333;}#mermaid-svg-cKUlSGERzv5OFidy .cluster-label span p{background-color:transparent;}#mermaid-svg-cKUlSGERzv5OFidy .label text,#mermaid-svg-cKUlSGERzv5OFidy span{fill:#333;color:#333;}#mermaid-svg-cKUlSGERzv5OFidy .node rect,#mermaid-svg-cKUlSGERzv5OFidy .node circle,#mermaid-svg-cKUlSGERzv5OFidy .node ellipse,#mermaid-svg-cKUlSGERzv5OFidy .node polygon,#mermaid-svg-cKUlSGERzv5OFidy .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-cKUlSGERzv5OFidy .rough-node .label text,#mermaid-svg-cKUlSGERzv5OFidy .node .label text,#mermaid-svg-cKUlSGERzv5OFidy .image-shape .label,#mermaid-svg-cKUlSGERzv5OFidy .icon-shape .label{text-anchor:middle;}#mermaid-svg-cKUlSGERzv5OFidy .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-cKUlSGERzv5OFidy .rough-node .label,#mermaid-svg-cKUlSGERzv5OFidy .node .label,#mermaid-svg-cKUlSGERzv5OFidy .image-shape .label,#mermaid-svg-cKUlSGERzv5OFidy .icon-shape .label{text-align:center;}#mermaid-svg-cKUlSGERzv5OFidy .node.clickable{cursor:pointer;}#mermaid-svg-cKUlSGERzv5OFidy .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-cKUlSGERzv5OFidy .arrowheadPath{fill:#333333;}#mermaid-svg-cKUlSGERzv5OFidy .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-cKUlSGERzv5OFidy .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-cKUlSGERzv5OFidy .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cKUlSGERzv5OFidy .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-cKUlSGERzv5OFidy .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cKUlSGERzv5OFidy .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-cKUlSGERzv5OFidy .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-cKUlSGERzv5OFidy .cluster text{fill:#333;}#mermaid-svg-cKUlSGERzv5OFidy .cluster span{color:#333;}#mermaid-svg-cKUlSGERzv5OFidy div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-cKUlSGERzv5OFidy .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-cKUlSGERzv5OFidy rect.text{fill:none;stroke-width:0;}#mermaid-svg-cKUlSGERzv5OFidy .icon-shape,#mermaid-svg-cKUlSGERzv5OFidy .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cKUlSGERzv5OFidy .icon-shape p,#mermaid-svg-cKUlSGERzv5OFidy .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-cKUlSGERzv5OFidy .icon-shape .label rect,#mermaid-svg-cKUlSGERzv5OFidy .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cKUlSGERzv5OFidy .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-cKUlSGERzv5OFidy .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-cKUlSGERzv5OFidy :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 上下文切换触发时机
自愿切换
非自愿切换
等待 I/O
调用 sleep
等待锁
时间片用完
被抢占
中断触发调度

图 9:自愿切换与非自愿切换。 自愿切换是进程主动放弃 CPU,非自愿切换是被迫放弃。

七、如何减少上下文切换

上下文切换是必要的,但过多的切换会降低系统性能。以下是一些减少上下文切换的方法。

7.1 调整时间片大小

时间片太小,切换频繁;时间片太大,响应变差。需要根据系统负载调整时间片。

7.2 使用线程而非进程

线程切换比进程切换开销小得多。如果任务之间需要共享数据,使用多线程比多进程更高效。

7.3 减少锁竞争

锁竞争会导致线程频繁阻塞和唤醒,增加上下文切换。可以通过减小锁粒度、使用无锁数据结构等方法减少锁竞争。

7.4 使用 I/O 多路复用

select、poll、epoll 等 I/O 多路复用技术可以让一个线程管理多个 I/O 连接,减少线程数量和上下文切换。

7.5 使用协程

协程是用户态的轻量级线程,切换在用户态完成,不需要进入内核,开销远小于线程切换。
#mermaid-svg-5eBfMyVD64zOuWaX{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-5eBfMyVD64zOuWaX .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5eBfMyVD64zOuWaX .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5eBfMyVD64zOuWaX .error-icon{fill:#552222;}#mermaid-svg-5eBfMyVD64zOuWaX .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5eBfMyVD64zOuWaX .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5eBfMyVD64zOuWaX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5eBfMyVD64zOuWaX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5eBfMyVD64zOuWaX .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5eBfMyVD64zOuWaX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5eBfMyVD64zOuWaX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5eBfMyVD64zOuWaX .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5eBfMyVD64zOuWaX .marker.cross{stroke:#333333;}#mermaid-svg-5eBfMyVD64zOuWaX svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5eBfMyVD64zOuWaX p{margin:0;}#mermaid-svg-5eBfMyVD64zOuWaX .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-5eBfMyVD64zOuWaX .cluster-label text{fill:#333;}#mermaid-svg-5eBfMyVD64zOuWaX .cluster-label span{color:#333;}#mermaid-svg-5eBfMyVD64zOuWaX .cluster-label span p{background-color:transparent;}#mermaid-svg-5eBfMyVD64zOuWaX .label text,#mermaid-svg-5eBfMyVD64zOuWaX span{fill:#333;color:#333;}#mermaid-svg-5eBfMyVD64zOuWaX .node rect,#mermaid-svg-5eBfMyVD64zOuWaX .node circle,#mermaid-svg-5eBfMyVD64zOuWaX .node ellipse,#mermaid-svg-5eBfMyVD64zOuWaX .node polygon,#mermaid-svg-5eBfMyVD64zOuWaX .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5eBfMyVD64zOuWaX .rough-node .label text,#mermaid-svg-5eBfMyVD64zOuWaX .node .label text,#mermaid-svg-5eBfMyVD64zOuWaX .image-shape .label,#mermaid-svg-5eBfMyVD64zOuWaX .icon-shape .label{text-anchor:middle;}#mermaid-svg-5eBfMyVD64zOuWaX .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-5eBfMyVD64zOuWaX .rough-node .label,#mermaid-svg-5eBfMyVD64zOuWaX .node .label,#mermaid-svg-5eBfMyVD64zOuWaX .image-shape .label,#mermaid-svg-5eBfMyVD64zOuWaX .icon-shape .label{text-align:center;}#mermaid-svg-5eBfMyVD64zOuWaX .node.clickable{cursor:pointer;}#mermaid-svg-5eBfMyVD64zOuWaX .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-5eBfMyVD64zOuWaX .arrowheadPath{fill:#333333;}#mermaid-svg-5eBfMyVD64zOuWaX .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5eBfMyVD64zOuWaX .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5eBfMyVD64zOuWaX .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5eBfMyVD64zOuWaX .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-5eBfMyVD64zOuWaX .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5eBfMyVD64zOuWaX .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-5eBfMyVD64zOuWaX .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5eBfMyVD64zOuWaX .cluster text{fill:#333;}#mermaid-svg-5eBfMyVD64zOuWaX .cluster span{color:#333;}#mermaid-svg-5eBfMyVD64zOuWaX div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-5eBfMyVD64zOuWaX .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5eBfMyVD64zOuWaX rect.text{fill:none;stroke-width:0;}#mermaid-svg-5eBfMyVD64zOuWaX .icon-shape,#mermaid-svg-5eBfMyVD64zOuWaX .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5eBfMyVD64zOuWaX .icon-shape p,#mermaid-svg-5eBfMyVD64zOuWaX .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-5eBfMyVD64zOuWaX .icon-shape .label rect,#mermaid-svg-5eBfMyVD64zOuWaX .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5eBfMyVD64zOuWaX .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-5eBfMyVD64zOuWaX .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-5eBfMyVD64zOuWaX :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 减少上下文切换
调整时间片
使用线程而非进程
减少锁竞争
I/O 多路复用
使用协程

图 10:减少上下文切换的方法。

八、上下文切换的实际应用

8.1 Linux 中的上下文切换

Linux 使用 switch_to 宏完成进程上下文切换。它保存当前进程的寄存器,恢复下一个进程的寄存器,并切换栈和页表。

8.2 容器与上下文切换

容器共享宿主机内核,容器内的进程切换仍然是普通的进程切换。但容器启动比虚拟机快,因为不需要启动完整的内核。

8.3 高性能计算中的上下文切换

在高性能计算中,上下文切换是性能杀手。例如,高频交易系统要求极低的延迟,通常会:

  • 使用 CPU 亲和性,把进程绑定到固定 CPU;
  • 使用轮询而非中断,避免中断上下文切换;
  • 使用用户态网络协议栈,绕过内核。

#mermaid-svg-R3C5j9qdvjCJyE2J{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-R3C5j9qdvjCJyE2J .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-R3C5j9qdvjCJyE2J .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-R3C5j9qdvjCJyE2J .error-icon{fill:#552222;}#mermaid-svg-R3C5j9qdvjCJyE2J .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-R3C5j9qdvjCJyE2J .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-R3C5j9qdvjCJyE2J .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-R3C5j9qdvjCJyE2J .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-R3C5j9qdvjCJyE2J .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-R3C5j9qdvjCJyE2J .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-R3C5j9qdvjCJyE2J .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-R3C5j9qdvjCJyE2J .marker{fill:#333333;stroke:#333333;}#mermaid-svg-R3C5j9qdvjCJyE2J .marker.cross{stroke:#333333;}#mermaid-svg-R3C5j9qdvjCJyE2J svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-R3C5j9qdvjCJyE2J p{margin:0;}#mermaid-svg-R3C5j9qdvjCJyE2J .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-R3C5j9qdvjCJyE2J .cluster-label text{fill:#333;}#mermaid-svg-R3C5j9qdvjCJyE2J .cluster-label span{color:#333;}#mermaid-svg-R3C5j9qdvjCJyE2J .cluster-label span p{background-color:transparent;}#mermaid-svg-R3C5j9qdvjCJyE2J .label text,#mermaid-svg-R3C5j9qdvjCJyE2J span{fill:#333;color:#333;}#mermaid-svg-R3C5j9qdvjCJyE2J .node rect,#mermaid-svg-R3C5j9qdvjCJyE2J .node circle,#mermaid-svg-R3C5j9qdvjCJyE2J .node ellipse,#mermaid-svg-R3C5j9qdvjCJyE2J .node polygon,#mermaid-svg-R3C5j9qdvjCJyE2J .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-R3C5j9qdvjCJyE2J .rough-node .label text,#mermaid-svg-R3C5j9qdvjCJyE2J .node .label text,#mermaid-svg-R3C5j9qdvjCJyE2J .image-shape .label,#mermaid-svg-R3C5j9qdvjCJyE2J .icon-shape .label{text-anchor:middle;}#mermaid-svg-R3C5j9qdvjCJyE2J .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-R3C5j9qdvjCJyE2J .rough-node .label,#mermaid-svg-R3C5j9qdvjCJyE2J .node .label,#mermaid-svg-R3C5j9qdvjCJyE2J .image-shape .label,#mermaid-svg-R3C5j9qdvjCJyE2J .icon-shape .label{text-align:center;}#mermaid-svg-R3C5j9qdvjCJyE2J .node.clickable{cursor:pointer;}#mermaid-svg-R3C5j9qdvjCJyE2J .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-R3C5j9qdvjCJyE2J .arrowheadPath{fill:#333333;}#mermaid-svg-R3C5j9qdvjCJyE2J .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-R3C5j9qdvjCJyE2J .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-R3C5j9qdvjCJyE2J .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-R3C5j9qdvjCJyE2J .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-R3C5j9qdvjCJyE2J .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-R3C5j9qdvjCJyE2J .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-R3C5j9qdvjCJyE2J .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-R3C5j9qdvjCJyE2J .cluster text{fill:#333;}#mermaid-svg-R3C5j9qdvjCJyE2J .cluster span{color:#333;}#mermaid-svg-R3C5j9qdvjCJyE2J div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-R3C5j9qdvjCJyE2J .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-R3C5j9qdvjCJyE2J rect.text{fill:none;stroke-width:0;}#mermaid-svg-R3C5j9qdvjCJyE2J .icon-shape,#mermaid-svg-R3C5j9qdvjCJyE2J .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-R3C5j9qdvjCJyE2J .icon-shape p,#mermaid-svg-R3C5j9qdvjCJyE2J .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-R3C5j9qdvjCJyE2J .icon-shape .label rect,#mermaid-svg-R3C5j9qdvjCJyE2J .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-R3C5j9qdvjCJyE2J .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-R3C5j9qdvjCJyE2J .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-R3C5j9qdvjCJyE2J :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 上下文切换应用
Linux: switch_to 宏
容器: 普通进程切换
高性能计算: 减少切换

图 11:上下文切换的实际应用。

九、常见误区澄清

误区 真相
"上下文切换就是模式切换" 模式切换是用户态到内核态,上下文切换是进程切换,两者不同
"线程切换和进程切换开销一样" 线程切换不需要切换页表,开销小得多
"上下文切换没有开销" 上下文切换涉及保存恢复寄存器、切换页表、刷新 TLB,开销较大
"系统调用一定会导致上下文切换" 不一定,如果不需要切换进程,只发生模式切换
"上下文切换越多越好" 过多切换会降低性能,需要平衡
"所有操作系统的上下文切换机制相同" Linux、Windows 的实现细节不同,但核心思想一致
"上下文切换只发生在进程之间" 线程之间、中断处理也会发生上下文切换
相关推荐
吹什么轩2 小时前
linux系统复习:僵尸进程与孤儿进程
linux·运维·php
张宇Joaquin2 小时前
AMD uProf 工具采集微架构特征使用介绍
服务器
殷忆枫2 小时前
告别依赖地狱!在 Ubuntu 上用 Docker 极速部署 Home Assistant 与 MQTT,并接入 Siri 与嵌入式 C 终端
linux·ubuntu·docker
第404号工位3 小时前
手机到底有没有偷听我们?我抓包了 72 小时,抓到了真凶
linux·人工智能·架构
老李IT笔记3 小时前
连不上不一定是网不好:新系统不认的服务端配置卡在哪一档
运维·服务器·网络
字节跳动开源3 小时前
ByteDance 2026 上半年 Linux 内核贡献回顾
linux·开源
小此方3 小时前
Linux网络(二十八):从NAT转换到正反向代理:图解内网通信、NAPT端口映射
linux·运维·网络
刚入门的大一新生3 小时前
Linux-进程池
linux·运维·服务器
鱼很腾apoc4 小时前
【MySQL】第4期 用户管理与 C 语言连接编程详解
linux·服务器·c语言·mysql·connector/c
刚入门的大一新生4 小时前
Linux-进程间通信1
linux·运维·服务器