深入分析Linux上下文与上下文切换

Linux 进程运行空间与特权等级

在 Linux 操作系统中,进程的运行空间被划分为内核空间和用户空间,这种划分是为了保护系统的稳定性和安全性。这两个空间对应着 CPU 的特权等级,分别为:

  • Ring 0(内核态)
  • Ring 3(用户态)
  • 本文将深入介绍这两个空间的概念、特权等级的含义以及它们之间的切换机制。

内核空间与用户空间

内核空间

内核空间是操作系统内核运行的区域,拥有最高的特权等级。在内核空间中,操作系统可以执行任意指令,访问所有硬件和内存资源。这包括对系统硬件、设备驱动程序和核心数据结构的完全访问。内核空间通常包含了操作系统的内核代码和数据结构。

用户空间

用户空间是供用户程序执行的区域,拥有较低的特权等级。在用户空间中,程序只能执行受限的指令,且对硬件资源的直接访问受到限制。用户空间包含了用户应用程序的代码和数据,以及一些共享库和用户环境的运行时信息。

CPU 特权等级

CPU 特权等级用于区分不同程序对计算机系统资源的访问权限。在 x86 架构中,特权等级被分为四个环,分别是:

  • Ring 0
  • Ring 3

Ring 0 拥有最高特权,而 Ring 3 拥有最低特权。

1. Ring 0 - 内核态

    Ring 0 是最高特权等级,对应内核空间。在 Ring 0 中,操作系统内核运行,可以执行任意指令,访问系统的全部资源。内核态下运行的代码可以执行特权指令,例如修改全局描述符表(GDT)和局部描述符表(LDT),以及执行 I/O 操作。

2. Ring 3 - 用户态

    Ring 3 是最低特权等级,对应用户空间。在 Ring 3 中,运行用户应用程序,程序只能执行非特权指令,访问受限资源。用户态下运行的代码无法直接执行一些特权指令,例如修改 GDT 和 LDT。必须通过系统调用陷入到内核中,才能访问这些特权资源。

上下文

Linux 是一个多任务操作系统,支持远远大于cpu数量的任务并行运行,但是从底层上看其实这些任务也不是同时运行,而是操作系统在非常短的时间内把CPU轮流分配给这些任务,这样在表象看起来像是多任务同时运行一样。

因为这些任务实际上是轮流使用cpu,所以在任务运行之前就得有地方记录这些任务的运行信息(需要加载什么信息,在哪里开始运行等)--CPU 寄存器和程序计数器。

在 Linux 操作系统中,当操作系统进行进程上下文切换时,通常会保存和恢复CPU 寄存器的状态,以及程序计数器的值。这确保了在切换回进程时,它能够继续执行先前被中断的位置。这是操作系统实现多任务和多进程并发执行的基本机制之一。

CPU 寄存器

  • 含义: CPU 寄存器是一组用于暂时存储数据的小型存储区域,直接嵌入在 CPU 中。寄存器在计算机中起到非常关键的作用,用于存储临时数据、地址、状态等信息。

  • 关联进程资源: 寄存器包括通用寄存器、特殊用途寄存器等。在进程上下文切换时,通用寄存器的值通常会被保存到进程的上下文中,以便在切换回该进程时能够恢复到之前的状态。

程序计数器(Program Counter,PC)

  • 含义: 程序计数器是一种特殊的寄存器,用于存储当前正在执行的指令的地址,即程序的下一条指令的地址。

  • 关联进程位置: 程序计数器的值指示了进程在内存中的特定位置,表示即将执行的指令的地址。在进程执行期间,计算机会不断更新程序计数器的值,使其指向下一条要执行的指令的地址。

CPU 寄存器和程序计数器。都是 CPU 在运行任何任务前,必须的依赖环境,因此也被叫做 CPU 上下文。

一句话总结上下文:

    在每个任务运行前,cpu需要知道任务是从哪儿运行的,然后从哪儿开始的,也就是说,需要系统给它设置好 CPU寄存器和程序计数器, cpu的寄存器是,cpu内置的容量小,但是速度极快的内存,而程序计数器,则是用来存储正在执行的指令位置,或者即将执行的吓一跳指令位置。他们是cpu在运行任何任务前,都必须依赖的环境(包括寄存器状态、内存映射、打开的文件、进程优先级等),因此也被叫做CPU上下文。

一句话总结上下文切换:

    就是先把前一个任务的 CPU 上下文(也就是 CPU 寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。

上下文切换

上下文切换是指操作系统在多任务环境下,从一个任务切换到另一个任务时保存和恢复这些上下文信息的过程。在 Linux 系统中,上下文和上下文切换是操作系统中关键的概念,对于系统性能和多任务处理有着重要的影响。

在多任务操作系统中,CPU 上下文切换是实现并发执行的关键机制。根据任务的不同,可以把上下文切换可以分成三种不同的上下文切换场景:进程上下文切换、线程上下文切换以及中断上下文切换。我们将从底层原理出发,详细介绍每种场景的具体实现和影响因素。

进程上下文切换

进程的上下文切换

    进程上下文切换是指从一个进程切换到另一个进程。它发生在多任务系统中,由调度器负责决定哪个进程获得 CPU 时间。上下文切换的开销包括保存当前进程的上下文、加载新进程的上下文以及刷新内存映射等。

系统调用的上下文切换

    在一开始介绍进程的运行空间与系统等级的时候,进程在从用户态到内核态的转变涉及系统调用,这里的系统调用也涉及上下文切换。系统调用是用户程序请求内核执行特权操作的方式,例如打开、读取或关闭文件。当进行文件内容查看等操作时,需要多次系统调用完成。每次系统调用都引发了 CPU 上下文的切换。

具体过程如下:

  1. 保存用户态: 在系统调用开始时,CPU 寄存器里保存着用户态的指令位置,需要先保存这些信息以便后续恢复。

  2. 进入内核态: 为了执行内核态代码,CPU 寄存器需要更新为内核态指令的新位置。

  3. 执行内核任务: 此时,CPU 进入内核态并执行相应的内核任务,完成系统调用的操作。

  4. 恢复用户态: 系统调用结束后,CPU 寄存器需要恢复原来保存的用户态,然后切换回用户空间,继续运行进程。

一次系统调用的过程实际上发生了两次 CPU 上下文切换。

虽然系统调用过程中不涉及虚拟内存等用户态资源的切换,也不会切换进程,但实际上,CPU 的上下文切换是无法避免的。因此,系统调用过程中的上下文切换通常被称为特权模式切换,而非上下文切换。

进程上下文切换与系统调用的区别

进程上下文切换与系统调用有明显区别:

  1. 上下文内容:

    进程上下文切换包括了虚拟内存、栈、全局变量等用户空间的资源,还包括了内核堆栈、寄存器等内核空间的状态。

    系统调用时,只保存和恢复了 CPU 寄存器和用户态的状态。

  2. 切换对象:

    进程上下文切换是在不同进程之间进行的

    系统调用过程中一直是同一个进程在运行

  3. 过程复杂度:

    进程上下文切换相对于系统调用更为复杂。它需要保存当前进程的内核状态和 CPU 寄存器之前,还需要保存该进程的虚拟内存、栈等;加载下一进程的内核态后,还需要刷新进程的虚拟内存和用户栈。

进程上下文切换的开销

上下文切换的过程并非“免费”,它需要内核在 CPU 上运行来完成。根据Tsuna的实验数据,每次上下文切换都需要几十纳秒到数微秒的 CPU 时间。在进程上下文切换次数较多的情况下,容易导致 CPU 时间主要花费在资源的保存和恢复上,而非真正的进程执行。

进程调度与上下文切换的时机

在 Linux 系统中,进程的调度并不仅仅发生在进程执行完终止的时候。我们来逐一梳理几个触发进程调度的场景,以加深对进程调度机制的理解。

1. 时间片耗尽
时机:
  • 当前运行进程的时间片耗尽。

为了保证所有进程能够得到公平调度,CPU 时间被划分为一段段的时间片,这些时间片轮流分配给各个进程。当某个进程的时间片耗尽时,系统会挂起该进程,并切换到等待 CPU 的其他进程运行。

2. 系统资源不足
时机:
  • 进程等待某些系统资源(如内存)。

在系统资源不足的情况下(例如内存不足),进程需要等待资源满足才能继续运行。此时,该进程会被挂起,并由系统调度其他等待 CPU 的进程运行。

3. 睡眠函数
时机:
  • 进程主动调用睡眠函数(如 sleep)。

通过睡眠函数(如 sleep)等方式,进程可以主动挂起自己,等待一定的时间后再次被调度运行。

  1. 进程进入睡眠状态,不再占用 CPU 资源。

  2. 睡眠时间结束或被唤醒后,进程重新被调度运行。

4. 优先级更高的进程
时机:
  • 高优先级进程就绪并准备运行。

当有优先级更高的进程就绪时,为了确保高优先级进程能够及时运行,当前进程会被挂起,系统调度高优先级进程运行。

  1. 低优先级进程被挂起。

  2. 高优先级进程获得 CPU 控制权,运行相应任务。

  3. 执行完任务后,系统可能重新调度低优先级进程。

5. 硬件中断
时机:
  • 硬件设备产生中断。

发生硬件中断时,CPU 上正在执行的进程会被中断挂起,转而执行内核中的中断服务程序。一旦中断处理完毕,原先的进程可能会被重新调度运行。

  1. 当前进程被中断挂起。

  2. 中断服务程序执行。

  3. 中断处理完成后,可能重新调度原先的进程继续执行。

线程上下文切换

    线程上下文切换与进程上下文切换类似,但开销更小。因为线程共享相同的地址空间,切换时无需刷新内存映射。线程上下文切换通常发生在同一进程内的不同线程之间。

    线程(Thread)和进程(Process)是操作系统中用于执行程序的两个基本概念,在开始分析之前,我们先了解下线程与进程:线程是调度的基本单位,而进程则是资源拥有的基本单位

  1. 任务调度:

    • 线程是操作系统进行任务调度的基本单位。内核可以调度多个线程在同一进程中并发执行,充分利用多核处理器的性能。

    • 进程是一个独立的执行环境,它包含至少一个线程。但在内核的任务调度中,调度的对象是线程,而非整个进程。

  2. 资源拥有:

    • 进程是独立的资源拥有者,拥有独立的地址空间、文件描述符等。不同进程之间的资源是相互独立的。

    • 线程共享相同进程的资源,包括虚拟内存、文件描述符等。线程间的通信相对简单,因为它们共享相同的地址空间。

    • 线程也有自己的私有数据,比如栈和寄存器等。

  3. 调度效率:

    • 由于线程共享相同的资源,线程的创建、销毁和切换开销相对较小,调度效率较高。

    • 进程的独立性导致了较大的创建、销毁和切换开销,因为这涉及到整个地址空间的切换。

  4. 错误影响范围:

    • 一个线程的错误可能影响整个进程,因为它们共享相同的资源。这需要更加谨慎的编程和调试。

    • 进程的独立性使得一个进程的错误不太可能直接影响其他进程,提高了系统的稳定性。

线程上下文切换 可以分为两种情况

  1. 前后线程属于不同的进程。因为资源不共享,所以上下文切换的过程与进程上下文切换时一样的。

  2. 如果前后两个线程属于一个进程。因为虚拟内存是共享的,所以切换的时候 虚拟内存等资源是不用动的,只需要切换不同线程自己拥有的私有数据,寄存器等不共享的数据。

中断上下文切换

中断上下文切换是由硬件中断或软件中断触发的。当中断发生时,操作系统会保存当前进程或线程的上下文,然后转入中断服务例程执行。执行完中断服务例程后,操作系统会恢复之前保存的上下文,继续执行被中断的进程或线程。

中断上下文切换与进程上下文切换有着明显的区别。中断上下文切换并不涉及到进程的用户态,因此在中断过程中打断了一个正处在用户态的进程时,不需要保存和恢复这个进程的虚拟内存、全局变量等用户态资源。相比之下,中断上下文只包括内核态中断服务程序执行所必需的状态,主要包括 CPU 寄存器、内核堆栈、硬件中断参数等。

中断上下文切换的特点:

  1. 内核态执行:

    • 中断上下文切换是在内核态下执行的,与用户态进程无关。因此,不需要保存和恢复用户态的资源。

  2. 资源限定:

    • 中断上下文主要关注于提供中断服务所需的最少资源,包括 CPU 寄存器、内核堆栈、硬件中断参数等。

    • 与进程上下文切换相比,中断上下文切换的资源范围较为有限,着重于满足中断处理的基本需求。

  3. 无需虚拟内存切换:

    • 由于中断上下文不牵涉用户态,因此无需切换虚拟内存。不同进程的虚拟内存空间在中断上下文中并不影响。

  4. 快速执行:

    • 中断上下文切换的目标是尽快响应硬件中断,因此切换过程相对迅速。

    • 这与进程上下文切换不同,后者可能涉及到更多的资源保存和恢复,因而相对较慢。

中断上下文切换的设计目标是最小化对系统性能的影响,专注于提供必要的执行环境以迅速处理硬件中断。这种机制使得操作系统能够高效地响应外部事件,保证系统的可靠性和实时性。

总结

上下文和上下文切换是操作系统中的关键概念,直接影响系统的性能和响应能力。了解上下文的概念以及上下文切换的过程有助于理解操作系统的工作原理,并能够优化程序以提高系统的性能和效率。在设计和开发多任务应用程序时,合理处理上下文切换是至关重要的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/595691.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Lightroom Classic 2024成就专业摄影梦想mac/win版

Lightroom Classic 2024是一款功能强大的数字图像处理和管理工具,专为摄影师和摄影爱好者设计。它提供了丰富的照片调整、处理、管理和分享功能,帮助用户轻松管理、编辑和展示他们的照片。 Lightroom Classic 2024软件获取 首先,Lightroom C…

晶核2024搬砖职业推荐!

在晶核手游的广袤世界中,选择一位适合自己的搬砖角色是每位玩家都必须认真考虑的事情。不同的职业拥有独特的技能和特点,能够在搬砖过程中发挥不同的优势。下面,我们将深入探讨晶核搬砖的四大利器,让你对每个角色有更深入的了解&a…

Linux网络管理类命令

ping -c:指定次数 -i n:指定发送频率 n 秒 -t:指定 TTL 值 -s:指定发送包的大小 ifconfig iproute netstat -anltp ss ssh 主机名 SCP wget nmap -A: 全面扫描 -p :端口 80 22-80 80,25,443 -sP &#xf…

Java集合(个人整理笔记)

目录 1. 常见的集合有哪些? 2. 线程安全的集合有哪些?线程不安全的呢? 3. Arraylist与 LinkedList 异同点? 4. ArrayList 与 Vector 区别? 5. Array 和 ArrayList 有什么区别?什么时候该应 Array而不是…

数据结构之顺序表的相关知识点及应用

个人主页(找往期文章包括但不限于本期文章中不懂的知识点):我要学编程(ಥ_ಥ)-CSDN博客 目录 顺序表的概念及结构 顺序表的分类 顺序表的实现 在顺序表中增加数据 在顺序表中删除数据 在顺序表中查找数据 顺序表源码 顺序表的概念…

mustache模板引擎学习记录

0.历史上曾经出现的数据变为视图的方法 1.纯DOM法 let arr [{"name":"张三","age":18,"sex":"男"}, ] let list document.querySelector(#list) for (let i 0; i < arr.length; i) {let li document.createElement(…

JavaScript权威指南(第7版) 笔记 - 扩展操作符总结

扩展操作符 ... &#xff0c;不是真正意义上的JavaScript操作符。 let str "0123ABC" console.log(typeof ...str);// Uncaught SyntaxError: Unexpected token ... 上面的第2行代码会报错&#xff0c;扩展操作符 ... 只能在数组字面量、对象字面量、函数调用中使…

虚拟主机、VPS主机和云服务器的区别

对于每个建站新手来说&#xff0c;首先要解决的就是服务器购买的问题&#xff0c;目前市面有很多类型的服务器&#xff0c;常见的有&#xff1a;阿里云、腾讯云、Vultr云服务器&#xff0c;也有RackNerd、Cloudways等提供的VPS&#xff0c;还有SiteGround、ChemiCloud 、 Hosti…

selenium 遮罩层

之前写智联自动投简历 和boss自动投简历的时候 发现操作到上限之后就有个遮罩层&#xff0c;会在当前页面有个顶层得div 没办法获取下面的内容 # 假设遮罩层元素有一个特定的ID或者其他属性 没有id xpath 或者class 都可以mask_element WebDriverWait(driver, 10).until(EC.…

SV学习笔记(七)

类型转换 写在前面 类型转换可以分为 静态转换和动态转换 。静态转换即需要在转换的表达式前 加上单引号 即可&#xff0c;该方式并不会对转换值做检查。如果发生转换失败&#xff0c;我们也无从得知。动态转换即需要使用 系统函数$cast(tgt&#xff0c; src) 做转换。静态转…

python文件打包找不到文件路径

引用&#xff1a;【将Python代码打包成exe可执行文件】 https://www.bilibili.com/video/BV1P24y1o7FY/?p4&share_sourcecopy_web&vd_sourced5811f31a0635dfc69a182c7bf1adb8b 在代码中&#xff0c;我们想读取文件a&#xff0c;一般使用如下方法。 import osdir os…

如何保护大模型API安全

大模型的崛起正在改变着我们对机器学习和人工智能的理解&#xff0c;它们不仅提供了令人惊叹的预测和分析能力&#xff0c;还在各行各业的应用中发挥着重要作用。通过提供 API&#xff0c;用户无需了解底层实现细节&#xff0c;使大型模型能够更好地与用户和应用程序进行交互&a…