cpu 上下文切换
设置好 cpu寄存器和程序计数器
依赖环境 因此叫做上下文
进程上下文切换 线程上下文切换 中断上下文切换
进程上下文切换
linux 按照特权等级 将进程的运行空间分为内核空间和用户空间
- 内核空间ring 0 具有最高权限 可以直接访问所有资源
- 用户空间 ring 3 只能访问受限资源 不能直接访问内存等硬件设备 必须通过系统调用陷入到内核中 才能访问这些特权资源
进程既可以在用户空间运行 也可以在内核空间中运行
- 用户态
- 内核态
从用户态到内核态的转变 需要通过系统调用来完成。
比如查看文件内容的时候,需要多次系统调用来完成,首先open()打开文件 然后read 读取文件内容 write 将内容写到标准输出 最后再close关闭文件
系统调用的过程中 有cpu上下文的切换
cpu寄存器里原来用户态的指令位置 需要先保存起来 接着为了执行内核态代码 cpu寄存器需要更新为内核态的新位置 最后才是跳到内核态运行内核任务
系统调用恢复之后cpu寄存器需要恢复 需要再切换一次
一次系统调用 发生了两次上下文切换
系统调用 被称为特权模式切换 而不是上下文切换
进程的切换只能发生在内核态 因此进程的上下文不仅包括了虚拟内存、栈、全局变量等用户空间的资源,还包括了内核堆栈、寄存器等内核空间的状态
进程的上下文切换 比系统调用多了一步
在保存当前进程的内核状态和cpu寄存器之前 需要先把该进程的虚拟内存、栈等保存起来 而加载下一进程的内核态之后 还需要刷新进程的虚拟内存和用户栈
进程一和进程二之间 包含进程1上下文保存和加载进程2上下文
每次上下文的切换 都需要几十纳秒到数微秒的cpu时间 这个时间还是相当可观的
线程和进程的最大区别在于 线程是调度的基本单位 而进程则是资源拥有的基本单位
进程只是給线程提供了虚拟内存、全局变量等资源
当进程只有一个线程时 可以认为进程就等于线程
线程会共享相同的虚拟内存和全局变量等资源 这些资源在上下文切换的时候 是不需要修改的
线程也有自己的私有数据 比如栈和寄存器
线程的切换
- 不属于同一进程的时候 因为资源不共享 所以切换和进程时一样的
- 属于同一进程 因为虚拟内存是共享的 只需要切换线程的私有数据结构 栈 寄存器这些不共享的数据
同进程内的线程切换 要比对进程之间的切换消耗更少的资源 这也是多线程代替多进程的一个优势
中断上下文切换
为了快速响应硬件的事件 中断处理会打断进程的正常调度和执行 转而调用中断处理程序 响应设备事件
中断上下文切换不涉及到进程的用户态
对同一个cpu来说 中断处理比进程拥有更高的优先级
cpu上下文切换 是保证linux系统正常工作的核心功能之一
过多的上下文切换 会把cpu时间消耗在寄存器 内核栈 虚拟内存等数据结构的保存和恢复上
1 | vmstat 5 |
- context switch
- interrupt
- r(running or runnable)
- b blocked 则是处于不可中断睡眠状态的进程数
1 | pidstat -w 5 |
1 | apt install sysbench |
1 | sysbench --threads=10 --max-time=300 threads run |
- 自愿上下文切换变多 说明进程都在等待资源 有可能发生了io等其他问题
- 非自愿上下文切换变多 说明进程都在被强制调度 都在争取cpu
- 中断次数变多说明cpu被中断处理程序占用 还需要通过查看 /proc/interrupts 具体问题具体分析