什么是上下文切换?进程切换时 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 的实现细节不同,但核心思想一致
"上下文切换只发生在进程之间" 线程之间、中断处理也会发生上下文切换
相关推荐
用户0510122572961 小时前
RGA(二)——RK3588 的核拓扑与能力差异
linux·嵌入式
用户0510122572961 小时前
RGA(一)——基础知识
linux·嵌入式
qetfw1 小时前
Debian 综合服务实训:Apache2、Samba、LDAP、vsftpd 与 OpenVPN
linux·服务器·debian
用户0510122572961 小时前
RGA(三)——实宽高、虚宽高与对齐约束
linux·嵌入式
fastjson_1 小时前
帆软看板 - 问题收集
linux·前端·javascript
jianpeng的工程笔记1 小时前
EL8 / EL9 安装 Slurm 26.05.4:主备控制器、MariaDB 记账与作业验收
linux·数据库·mariadb·高性能计算·slurm
程序员-Benothing1 小时前
Linux系统时间管理:date、timedatectl、NTP、Chrony配置
linux·运维·服务器
迪康Defender2 小时前
终端安全实践:浅谈端点安全管理系统内置终端防火墙能力
运维·服务器·网络·经验分享·安全·php·终端安全管理
AI备忘录2 小时前
(二十二)华为华三锐捷迈普思科 802.1X 端口认证配置命令(网络准入五厂商对照)
运维·服务器·开发语言·网络·安全·华为