当前位置: 首页 > news >正文

深入分析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. 快速执行:

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

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

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

总结

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

相关文章:

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

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

Docker快速上手及常用命令速查

Docker快速上手 安装 在ubuntu上安装docker: sudo apt-get install docker docker -v #查看版本在centos7上安装docker:(docker在YUM源的Extras仓库中) yum install docker systemctl start dockerdocker常用命令速查 #查看docker信息 docker info #查看本地镜…...

学习笔记:解决拖延

1 解决拖延、减轻压力的关键心态和方法 1.1 要点梳理 拖延是因为自己一直在逃避,重点是要有效突破逃避圈,进入学习圈,扩展成长圈。 毒蛇曲线(见思维导图)中越是临近截止期限,拖延的焦虑越上升&#xff0…...

第一个Swift程序

要创建第一个Swift项目,请按照以下步骤操作: 打开Xcode。如果您没有安装Xcode,可以在App Store中下载并安装它。在Xcode的欢迎界面上,选择“Create a new Xcode project”(创建新Xcode项目)。在模板选择界面上,选择“App”(应用程序)。在应用模板选择界面上,选择“Si…...

Anthropic Claude 3 加入亚马逊云科技 AI“全家桶”

编辑 | 宋慧 出品 | CSDN AIGC 每天都有新动态发生。最新的消息是亚马逊在 3 月底完成了对 Anthropic 的 40 亿美元投资(也是亚马逊 30 年来最大一笔外部投资),以及 GPT-4 最强对手的 Anthropic Claude 3 已经在亚马逊云科技 Amazon Bedrock…...

学习基于pytorch的VGG图像分类 day3

注:本系列博客在于汇总CSDN的精华帖,类似自用笔记,不做学习交流,方便以后的复习回顾,博文中的引用都注明出处,并点赞收藏原博主. 目录 VGG模型训练 1.导入必要的库 2.主函数部分 2.1使用cpu或gpu 2.2对数据…...

Spring Boot统一功能处理之拦截器

本篇主要介绍Spring Boot的统一功能处理中的拦截器。 目录 一、拦截器的基本使用 二、拦截器实操 三、浅尝源码 初始化DispatcherServerlet 处理请求(doDispatch) 四、适配器模式 一、拦截器的基本使用 在一般的学校或者社区门口,通常会安排几个…...

stm32之基本定时器的使用

在上文我们使用到了HAL库的自带的延时函数,HAL_Delay();我们来看一下函数的原型 __weak void HAL_Delay(uint32_t Delay) {uint32_t tickstart HAL_GetTick();uint32_t wait Delay;/* Add a freq to guarantee minimum wait */…...

单片机为什么还在用C语言编程?

单片机产品的成本是非常敏感的。因此对于单片机开发来说,最重要的是在极其有限的ROM和RAM中实现最多产品的功能。或者反过来说,实现相同的产品功能,所需要的ROM和RAM越小越好,在开始前我有一些资料,是我根据网友给的问…...

IO流的基础详解

文件【1】File类: 封装文件/目录的各种信息,对目录/文件进行操作,但是我们不可以获取到文件/目录中的内容。 【2】引入:IO流: I/O : Input/Output的缩写,用于处理设备之间的数据的传输。 【3】…...

实战攻防 | 记一次项目上的任意文件下载

1、开局 开局一个弱口令,正常来讲我们一般是弱口令或者sql,或者未授权 那么这次运气比较好,直接弱口令进去了 直接访问看看有没有功能点,正常做测试我们一定要先找功能点 发现一个文件上传点,不过老规矩,还…...

熔断之神:探寻Hystrix的秘密与实践指南

引言: 在微服务架构中,服务之间的依赖复杂且难以控制,容灾机制成为确保系统稳定性的重要手段。Hystrix作为Netflix开源的断路器实现,提供了一系列强健的容错功能。 Hystrix的核心概念与作用: Hystrix是一个由Netflix开…...

Web功能测试测试点总结!

web测试就是基于BS架构的软件产品的测试,通俗点来说就是web网站的测试。 一 、界面检查 当我们进入一个页面时,首先应该检查title,页面排版(即页面的展示),而不是马上进入字段校验页面面包屑导航是否正确当前位置是否可见 您的位…...

关于vue3的简单学习

Vue 3 简介 Vue 3 是一个流行的开源Java框架,用于构建用户界面和单页面应用。它带来了许多新特性和改进,包括更好的性能、更小的打包大小、更好的Type支持、全新的组合式 API,以及一些新的内置组件。 一. Vue 3 的新特性 Vue 3引入了许多新…...

windows server 2019 -DNS服务器搭建

前面是有关DNS的相关理论知识,懂了的可以直接跳到第五点。 说明一下:作为服务器ip最好固定下来,以DNS服务器为例子,如果客户机的填写DNS信息的之后,服务器的ip如果变动了的话,客户机都得跟着改&#xff0c…...

使用 XCTest 进行 iOS UI 自动化测试

使用 XCTest 进行 iOS UI 自动化测试是一种有效的方法,可以帮助你验证应用界面的行为和功能。以下是使用 XCTest 进行 iOS UI 自动化测试的基本步骤: 设置项目: 确保你的 Xcode 项目已经包含了 XCTest 测试目标。在测试目标中创建一个新的测试类&#xf…...

【Python】FANUC机器人OPC UA通信并记录数据

目录 引言机器人仿真环境准备代码实现1. 导入库2. 设置参数3. 日志配置4. OPC UA通信5. 备份旧CSV文件6. 主函数 总结 引言 OPC UA(Open Platform Communications Unified Architecture)是一种跨平台的、开放的数据交换标准,常用于工业自动化…...

Linux 中断处理

一、基本概念 1、中断及中断上下文 中断是一种由硬件设备产生的信号,不同设备产生的中断通过中断号来区分。CPU在接收到中断信号后,根据中断号执行对应的中断处理程序(Interrupt Service Routine) 内核对异常和中断的处理类似&a…...

人大金昌netcore适配,调用oracle模式下存储过程\包,返回参数游标

using KdbndpConnection conn new KdbndpConnection("Host192.168.133.221;Port54321;Databasedb1;Poolingtrue;User IDsystem;Password123");conn.Open();//存储过程调用也是类似using var cmd conn.CreateCommand();cmd.CommandText "模式.包名称.存储过程…...

pandas常用的一些操作

EXCLE操作 读取Excel data1 pd.read_excel(excle_dir) 读Excel取跳过前几行: data1 pd.read_excel(excle_dir,skiprows1) 获取总行数 data1.shape[0] 获取总列数 data1.shape[1] 指定某列数据类型 data1 pd.read_excel("C:数据导入.xlsx",dtype…...

【鸿蒙开发】系统组件Row

Row组件 Row沿水平方向布局容器 接口: Row(value?:{space?: number | string }) 参数: 参数名 参数类型 必填 参数描述 space string | number 否 横向布局元素间距。 从API version 9开始,space为负数或者justifyContent设置为…...

Hadoop和zookeeper集群相关执行脚本(未完,持续更新中~)

1、Hadoop集群查看状态 搭建Hadoop数据集群时,按以下路径操作即可生成脚本 [test_1analysis01 bin]$ pwd /home/test_1/hadoop/bin [test_01analysis01 bin]$ vim jpsall #!/bin/bash for host in analysis01 analysis02 analysis03 do echo $host s…...

蓝桥杯算法题:栈(Stack)

这道题考的是递推动态规划,可能不是很难,不过这是自己第一次靠自己想出状态转移方程,所以纪念一下: 要做这些题目,首先要把题目中会出现什么状态给找出来,然后想想他们的状态可以通过什么操作转移&#xf…...

JavaWeb-监听器

文章目录 1.基本介绍2.ServletContextListener1.基本介绍2.创建maven项目,导入依赖3.代码演示1.实现ServletContextListener接口2.配置web.xml3.结果 3.ServletContextAttributeListener监听器1.基本介绍2.代码实例1.ServletContextAttributeListener.java2.配置web…...

系统架构设计基础知识

一. 系统架构概述系统架构的定义 系统架构(System Architecture)是系统的一种整体的高层次的结构表示,是系统的骨架和根基,支撑和链接各个部分,包括构件、连接件、约束规范以及指导这些内容设计与演化的原理&#xff0…...

Vue自定义指令介绍及使用方法

介绍​ 除了 Vue 内置的一系列指令 (比如 v-model 或 v-show) 之外,Vue 还允许你注册自定义的指令 (Custom Directives)。 之前已经介绍了两种在 Vue 中重用代码的方式:组件 和 组合式函数。组件是主要的构建模块,而组合式函数则侧重于有状态…...

React 组件生命周期函数的用法和示例代码

React 中的生命周期函数可以分为三个阶段:Mounting(挂载),Updating(更新)和 Unmounting(卸载)。每个阶段都有不同的函数,用于执行不同的操作。 Mounting(挂载…...

【nginx运维】[emerg]: bind() to 0.0.0.0:80 failed (98: Address already in use)

关于nginx端口被占用的问题: If you get following error, when you try to start nginx… [emerg]: bind() to 0.0.0.0:80 failed (98: Address already in use) Then it means nginx or some other process is already using port 80. You can kill it using: su…...

浏览器工作原理与实践--虚拟DOM:虚拟DOM和实际的DOM有何不同

虚拟DOM是最近非常火的技术,两大著名前端框架React和Vue都使用了虚拟DOM,所以我觉得非常有必要结合浏览器的工作机制对虚拟DOM进行一次分析。当然了,React和Vue框架本身所蕴含的知识点非常多,而且也不是我们专栏的重点&#xff0c…...

arm工作模式、arm9通用寄存器、异常向量表中irq的异常向量、cpsr中的哪几位是用来设置工作模式以及r13,r14,15别名是什么?有什么作用?

ARM 首先先介绍一下ARM公司。 ARM成立于1990年11月,前身为Acorn计算机公司 主要设计ARM系列RISC处理器内核 授权ARM内核给生产和销售半导体的合作伙伴ARM公司不生产芯片 提供基于ARM架构的开发设计技术软件工具评估版调试工具应用软件总线架构外围设备单元等等CPU中…...