DP读书:《openEuler操作系统》(五)进程与线程

news2024/11/16 18:04:49

进程与线程

  • 进程的概念
    • 程序:从源码到执行
      • 1. 编译阶段:
      • 2. 加载阶段:
      • 3. 执行阶段:
    • 程序的并发执行与进程抽象
  • 进程的描述
    • 进程控制块
      • 1. 描述信息
      • 2. 控制信息
      • 3. CPU上下文
      • 4. 资源管理信息
    • 进程状态
      • 1.就绪状态
      • 2.运行状态
      • 3.阻塞状态
      • 4.终止状态
  • 进程的控制
    • 进程控制源语
      • 1.创建
      • 2.销毁
      • 3.阻塞与唤醒
    • 进程创建
      • 1.PCB的复制
      • 2.CPU上下文的复制
      • 3.地址空间的复制
    • 程序装载
      • 1.exec函数簇的系列函数接口
      • 2.可执行文件的寻找与打开
      • 3.可执行文件的装载
      • 4.新程序的执行
    • 进程终止
      • 1.用户资源的回收
      • 2.状态信息的发送与僵尸状态的设置
      • 3.内核资源的回收
      • 4.为所有子进程寻找新父进程
    • openEuler中的进程树

这章我啃了很久,作为计算机领域最为重要的两个概念之一,今天我想讲一讲进程的概念、描述、控制。这三小结的内容,差不多我每天啃一小节终于啃完了,那就敲吧~~~

现代计算机采用多道程序技术,允许多个程序并发执行,不同于早期的单道批处理系统计算机只能一次性处理一道的。而在这个过程中,程序只是对计算任务与数据的静态描述,并不能反应多道程序之间相互影响的这一状态。因此计算机系统中使用进程这一概念来反映程序在执行过程以及能来共享资源的基本单位。另外由于进程的创建于切换之间切换资源开销较大,操作系统中引入了线程这一概念。

进程的概念

程序:从源码到执行

下图展示了一份C语言源代码(符合C99标准),判断日期是否为闰年。

好的,以下是一份C语言源代码,用于判断给定日期是否为闰年:

#include <stdio.h>

int isLeapYear(int year) {
    if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
        return 1;
    } else {
        return 0;
    }
}

int main() {
    int year = 2024;
    if (isLeapYear(year)) {
        printf("%d is a leap year.\n", year);
    } else {
        printf("%d is not a leap year.\n", year);
    }
    return 0;
}

1. 编译阶段:

在编译阶段,编译器将源代码转换为机器代码。编译器首先检查代码的语法错误,例如拼写错误、缺失的括号等。如果源代码没有语法错误,编译器将创建一个可执行文件,其中包含计算机可以直接执行的机器代码。对于上述代码,编译器将检查变量和函数是否正确定义,然后将其转换为相应的机器代码。
闰年代码示例

以上为 C语言程序示例

gcc -o leap_year leap_year.c
./leap_year

以上为编译命令示意
用VScode来示例
为了使操作系统能够以标准方法对编译后二进制文件进行处理,类UNIX操作系统通常采用ELF格式(Executable and Linkable Format,可执行可链接文件格式)作为二进制文件的标准格式,ELF文件的执行视图如下:
ELF文件执行视图
ELF头部包含了描述整个ELF文件的基本信息,段头(Program Header)表包含了描述各个段(Segment)的信息,其中Segment是存储程序中数据或代码的逻辑结构。

在ELF(Executable and Linkable Format)中,有以下一些段(segments)是比较重要的:

  1. .text:这个段包含了程序的代码。这是执行程序时首先执行的段。它通常是可执行的,即它包含了那些被操作系统允许执行的指令。.text段通常被分为多个区段(section),包括.text.plt.got等。
  2. .data:这个段包含了初始化的全局变量和静态变量。这些数据在程序开始执行之前被加载到内存中,并被存储在只读和可写的方式。
  3. .rodata:这个段包含的是只读数据,比如常量,字符串字面量等。这些数据在程序开始执行之前被加载到内存,且只能被读取,不能被修改。
  4. .bss:这个段包含了未初始化的全局变量和静态变量。这些数据在程序开始执行之前被加载到内存,并被假定为零或空值。

这些不同的段在ELF文件和程序执行中扮演着重要的角色,它们描述了如何将程序的代码和数据加载到内存中,以及这些数据应该如何被操作系统和程序使用。

示例程序编译后的二进制可执行文件反汇编:

2. 加载阶段:

在加载阶段,操作系统将可执行文件加载到内存中,并准备开始执行。操作系统将分配必要的内存来存储程序的不同部分,例如代码、全局变量和堆栈。此外,操作系统还将设置程序所需的任何其他资源,例如打开文件句柄或分配网络连接。在这个阶段,程序的各种组成部分被放置在内存中适当的位置,并为执行做好准备。

操作系统把ELF文件装入内存,这个过程称为程序的加载。分为两步:1.解析ELF头部,进行程序加载,检查ELF文件格式是否被当前CPU架构支持;2.读取段头表获取每段的信息,加载至内存段分配内存空间。

3. 执行阶段:

程序加载之后,利用ELF找到程序入口。

在执行阶段,计算机开始执行程序。计算机从程序的main函数开始执行,即上述代码中的main()函数。在上述代码中,程序首先定义一个名为isLeapYear的函数,该函数接受一个整数参数year,并返回一个整数值。函数检查年份是否是闰年,如果是,则返回1,否则返回0。接下来,程序在main函数中调用isLeapYear函数,并打印结果。在这个阶段,CPU开始执行程序中的指令,并根据指令执行各种操作,例如读取和写入内存、执行算术运算等。根据上述代码,如果年份是闰年,程序将打印“2024是闰年”,否则将打印“2024不是闰年”。

程序在内存中的布局
对于程序执行过程中,动态申请的内存保存在一个称为堆的内存空间。让操作人员自主申请与及时释放。栈是先入后出的结构,在内存中,通常用低地址向高地址生长。上图,图四,为程序在内存中的布局。
程序栈的内容

程序的并发执行与进程抽象

进程的描述

进程控制块

进程控制块(Process Control Block,PCB)是操作系统用于管理进程的重要数据结构。它包含了关于进程的诸多信息,包括描述信息、控制信息、CPU上下文和资源管理信息。

1. 描述信息

描述信息主要包括以下部分:

  • 进程标识符(PID):用于唯一标识系统中的进程。
  • 进程状态:表示进程在执行过程中的状态,例如就绪、运行、等待或结束。
  • 父进程标识符:对于一个非初始进程,记录其父进程的PID。
  • 进程优先级:表示进程执行的优先级。

2. 控制信息

控制信息主要用于控制和协调进程的执行,包括以下部分:

  • 程序计数器(PC):指向下一条要执行的指令。
  • 栈指针:指向栈的顶部。
  • 中断向量:当发生中断时,指向中断处理程序的地址。
  • 信号掩码:用于屏蔽某些信号,防止它们中断程序的执行。
  • 调度参数:用于进程调度,例如估计运行时间、等待时间和剩余运行时间。

3. CPU上下文

CPU上下文记录了当前进程在CPU上执行所需的所有信息,包括以下部分:

  • 全局寄存器:例如程序计数器、栈指针等。
  • 局部寄存器:例如通用寄存器、状态寄存器等。
  • CPU的标志位:例如中断标志位、陷阱标志位等。
  • 堆栈:用于保存程序运行时的上下文信息。

4. 资源管理信息

资源管理信息用于记录和管理进程所需的资源,包括以下部分:

  • 打开文件表:记录进程打开的所有文件信息。
  • 内存管理信息:例如分页表、段表等,用于进程的内存管理。
  • 权限和安全信息:例如用户ID、组ID、文件权限等。
  • 进程间通信(IPC)信息:例如信号量、消息队列等,用于进程间的通信。
  • 其他资源:例如定时器、线程等。

进程状态

1.就绪状态

当进程已分配到必要的资源,并准备运行时,它处于就绪状态。在这种情况下,进程在等待CPU时间片的分配,一旦分配到时间片,它就可以被调度到CPU上执行。

2.运行状态

当进程正在占用CPU并执行其任务时,它处于运行状态。这是进程进行实际工作的状态。

3.阻塞状态

如果进程需要等待某些条件或资源才能继续执行,例如等待I/O操作完成,它就会进入阻塞状态。在这状态下,进程不会获得CPU时间片,直到它所需的资源或条件得到满足。

4.终止状态

当进程已完成任务或出现错误而不能继续执行时,它就处于终止状态。在这种情况下,进程不再占用CPU时间片,并且它的资源将被释放回系统,供其他进程使用。

进程的控制

进程控制源语

1.创建

创建一个新的进程。这通常由操作系统内核或用户程序发起。新的进程从父进程继承了许多属性,如代码、数据、内存配置、文件描述符等。

2.销毁

结束一个进程。这可以通过操作系统内核或用户程序发起。当一个进程结束时,它的资源(如内存、文件句柄等)会被回收,以便分配给其他进程。

3.阻塞与唤醒

进程在执行过程中可能遇到某种情况,使其无法继续执行,此时进程会进入阻塞状态。例如,当进程等待某个I/O操作完成时,它通常会进入阻塞状态。当阻塞的条件被满足时(例如,I/O操作完成),进程会被唤醒并回到就绪状态。

上述这些操作都是由操作系统提供的系统调用实现的。例如,在Unix和类Unix系统中,"fork()"系统调用用于创建新进程,"kill()"用于销毁进程,"wait()"用于阻塞进程直到其子进程结束。

进程创建

1.PCB的复制

PCB是操作系统用于管理进程的重要数据结构,其中包含了进程的各种信息,如进程标识符、状态、优先级、寄存器上下文等。在进程创建时,操作系统会为新进程创建一个新的PCB,并将父进程的PCB中的一些信息复制到子进程的PCB中,这些信息包括进程状态、优先级、寄存器上下文等。

2.CPU上下文的复制

CPU上下文是指当前进程在CPU上执行所需的各种信息,如寄存器状态、内存映射等。在进程创建时,操作系统会将父进程的CPU上下文复制到子进程的PCB中,以便子进程在CPU上执行时使用。

3.地址空间的复制

在进程创建时,操作系统还会为新进程分配一个独立的地址空间,这个地址空间是只读的,可以保证不同进程之间的数据隔离。父进程的地址空间会被复制到子进程的地址空间中,包括代码、数据、堆、栈等。当然,对于共享内存等特殊情况,操作系统会采取其他措施来管理不同进程之间的数据共享。

程序装载

程序装载是操作系统中一个重要的过程,它涉及到将可执行文件加载到内存中,并在CPU上执行。以下是程序装载的常见步骤:

1.exec函数簇的系列函数接口

在许多编程语言中,如C和C++,可以使用exec函数簇来装载和执行新的程序。这些函数包括exec()、execl()、execv()、execlp()等,它们接受一个或多个参数,指定要执行的新程序的路径和参数列表。调用这些函数后,当前进程的代码和数据将被替换为新程序的代码和数据。

需要注意的是,上述步骤仅适用于传统的静态链接的执行文件。对于动态链接的执行文件(如DLL或.so文件),装载的过程会有所不同,通常需要涉及到动态链接器的帮助。此外,不同的操作系统在具体实现上可能有所不同,但大致的流程是相似的。

2.可执行文件的寻找与打开

当调用exec函数簇时,需要提供要执行的可执行文件的路径。操作系统会解析这个路径,并在文件系统中寻找指定的可执行文件。一旦找到文件,操作系统会打开文件并准备将其加载到内存中。

3.可执行文件的装载

在可执行文件被打开后,操作系统将其从磁盘读入到内存中。这个过程称为“装载”,操作系统会根据可执行文件的二进制格式解析其内容,并将其映射到内存中的适当位置。装载过程涉及到一些底层的操作,如分配内存空间、设置内存保护等。

4.新程序的执行

一旦可执行文件被装载到内存中,操作系统会将CPU的控制权转移到新的程序中。新的程序从其入口点开始执行,入口点通常是程序的main()函数。此时,原来的进程将不复存在,取而代之的是新的程序在内存中的副本。

进程终止

进程终止是指一个正在运行的进程由于某种原因停止执行,结束其运行。在操作系统中,进程终止通常由系统或程序员通过发送终止信号来触发。当一个进程终止时,操作系统会执行一系列操作来清理和回收该进程所使用的资源,并确保该进程对系统的影响最小化。

1.用户资源的回收

在进程终止时,操作系统会回收该进程所使用的用户资源,例如打开的文件、分配的内存、创建的线程等。这些资源的回收可以防止资源泄漏和不必要的资源占用。回收这些资源可以确保其他进程可以使用这些资源,或者系统可以将其重新分配给其他需要的进程。

2.状态信息的发送与僵尸状态的设置

当一个进程终止时,操作系统会将其状态信息发送给父进程或操作系统本身。这些状态信息通常包括进程的PID、退出状态码(表示进程的结束状态)、时间戳等。在发送状态信息后,操作系统会将该进程的状态设置为“僵尸状态”,以表示该进程已经结束,但仍然占用着部分系统资源(例如内存)。

3.内核资源的回收

在进程终止后,操作系统会回收该进程所使用的内核资源,例如系统调用表、进程控制块(PCB)、虚拟内存空间等。这些资源的回收可以确保系统正常运行并防止资源泄漏。回收这些资源后,操作系统可以将这些资源重新分配给其他需要的进程。

4.为所有子进程寻找新父进程

在进程终止时,如果该进程有子进程,操作系统会为这些子进程寻找新的父进程。这是为了确保子进程不会成为孤儿进程,从而导致系统资源的浪费。寻找新父进程的过程通常涉及到操作系统的进程调度器,它会将一个父进程指定给子进程,以确保子进程可以被正确地管理和调度。

在进程终止后,操作系统会将其从进程调度中移除,并将其放入到一个适当的等待队列中,直到其状态被设置为僵尸状态并被彻底清理掉。整个过程是为了确保系统的稳定性和资源的有效利用。

openEuler中的进程树

1. 根进程(Root Process):根进程是整个进程树的起点,也是系统的第一个进程。在openEuler中,根进程的PID(进程ID)为0。
2. 系统进程(System Processes):系统进程是伴随着操作系统启动而生成的进程,它们负责维护操作系统的运行。在openEuler中,系统进程的PID通常以1开头。
3. 用户进程(User Processes):用户进程是由用户执行的程序产生的进程。在openEuler中,用户进程的PID以大于1的整数开头。
4. 子进程(Child Processes):子进程是根进程或系统进程派生出来的进程,它们通常执行一些特定的任务。子进程的PID与父进程的PID相关联。
5.僵尸进程(Zombie Processes):当子进程结束时,其父进程会为其回收资源并将其状态信息发送给内核。这个过程被称为“僵尸化”。僵尸进程已经结束,但仍然占用着部分资源(如内存),直到其父进程将其彻底清理掉。

在openEuler中,可以通过图形界面查看进程树。一种常用的方法是通过systemd工具。

以下是通过systemd工具在图形界面下查看进程树的步骤:

  1. 首先,确保你的系统中安装了systemd工具。如果你不确定是否已安装,可以通过以下命令进行安装:
sudo apt-get update
sudo apt-get install systemd-gui
  1. 安装完毕后,可以通过以下命令打开进程树:
systemctl --no-pager --state=running

这将在图形界面下显示当前正在运行的进程及其之间的关系。你可以通过这个图形界面浏览和查看各个进程的状态、PID等信息。

除了systemd工具外,还可以使用其他一些图形界面工具来查看进程树,如htop、glances等。这些工具通常需要在安装后才能使用,你可以通过包管理器进行安装。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第四章 C++的数据类型

系列文章目录 第一章 C的输入第二章 C的输出第三章 C的循环结构 文章目录 系列文章目录前言一、个人名片二、int三、char四、double总结 前言 今天来学数据类型&#xff01; 一、个人名片 个人主页&#xff1a;睡觉觉觉得 &#x1f390;CSDN新晋作者 &#x1f389;欢迎 &…

洛谷 P5717 三角形分类 C++代码

目录 前言 题目描述 思路点拨 优化 AC代码 AC截图 结尾 前言 马上就要突破10000浏览量了&#xff0c;再写一篇加加油&#xff01; 图片截图时间:2023.10.25.20:23 题目描述 网址&#xff1a;【深基3.习8】三角形分类 - 洛谷 思路点拨 这道题是给定三条边的长度&#…

BadNets:基于数据投毒的模型后门攻击代码(Pytorch)以MNIST为例

加载数据集 # 载入MNIST训练集和测试集 transform transforms.Compose([transforms.ToTensor(),]) train_loader datasets.MNIST(rootdata,transformtransform,trainTrue,downloadTrue) test_loader datasets.MNIST(rootdata,transformtransform,trainFalse) # 可视化样本 …

[Go版]算法通关村第十八关青铜——透析回溯的模版

目录 认识回溯思想回溯的代码框架从 N 叉树说起有的问题暴力搜索也不行回溯 递归 局部枚举 放下前任Go代码【LeetCode-77. 组合】回溯热身-再论二叉树的路径问题题目&#xff1a;二叉树的所有路径Go 代码 题目&#xff1a;路径总和 IIGo 代码 回溯是最重要的算法思想之一&am…

看我为了水作业速通 opengl freeglut!

参考视频计算机图形学基础–OpenGL的实现_哔哩哔哩_bilibiliT 图形绘制 点 GL_POINTS #define FREEGLUT_STATIC // Define a static library for calling functions #include <GL/freeglut.h> // Include the header filevoid myPoints() { //show three points in sc…

MySQL中大量数据优化方案

文章目录 1 大量数据优化1.1 引言1.2 评估表数据体量1.2.1 表容量1.2.2 磁盘空间1.2.3 实例容量 1.3 出现问题的原因1.4 解决问题1.4.1 数据表分区1.4.1.1 简介1.4.1.2 优缺点1.4.1.2 操作 1.4.2 数据库分表1.4.2.1 简介1.4.2.2 分库分表方案1.4.2.2.1 取模方案1.4.2.2.2 range…

JAVA毕业设计105—基于Java+Springboot+Vue的校园跑腿系统(源码+数据库)

基于JavaSpringbootVue的校园跑腿系统(源码数据库)105 一、系统介绍 本系统前后端分离 本系统分为管理员和用户两个角色 用户&#xff1a; 登录&#xff0c;注册&#xff0c;余额充值&#xff0c;密码修改&#xff0c;发布任务&#xff0c;接受任务&#xff0c;订单管理&…

(多线程)并发编程的三大基础应用——阻塞队列、定时器、线程池【手搓源码】

9.2 阻塞式队列 BlockingQueue<Integer> blockingQueue new LinkedBlockingQueue<Integer>();BlockingQueue<String> queue new LinkedBlockingQueue<>(); // 入队列 queue.put("abc"); // 出队列. 如果没有 put 直接 take, 就会阻塞. St…

IDEA 删除一次性删除所有断点

Ctrl Shift F8 &#xff08;打开“断点”对话框&#xff09; Ctrl A &#xff08;选择所有断点&#xff09; Alt Delete &#xff08;删除选定的断点&#xff09; Enter &#xff08;确认&#xff09;

数字孪生技术:工业数字化转型的引擎

数字孪生是一种将物理实体数字化为虚拟模型的技术&#xff0c;这些虚拟模型与其物理对应物相互关联。这种虚拟模型通常是在数字平台上创建的&#xff0c;它们复制了实际设备、工厂、甚至整个供应链的运作方式。这使工业企业能够实现以下益处&#xff1a; 1. 实时监测和分析 数…

(Java)中的数据类型和变量

文章目录 一、字面常量二、数据类型三、变量1.变量的概念2.语法的格式3.整型变量4.长整型变量5.短整型变量6.字节型变量 四、浮点型变量1.双精度浮点数2.单精度浮点数 五、字符型常量六、布尔型变量七、类型转换1.自动类型转换&#xff08;隐式&#xff09;2.强制类型转换(显式…

【数据结构】数组和字符串(四):特殊矩阵的压缩存储:稀疏矩阵——三元组表

文章目录 4.2.1 矩阵的数组表示4.2.2 特殊矩阵的压缩存储a. 对角矩阵的压缩存储b~c. 三角、对称矩阵的压缩存储d. 稀疏矩阵的压缩存储——三元组表结构体初始化元素设置打印矩阵主函数输出结果代码整合 4.2.1 矩阵的数组表示 【数据结构】数组和字符串&#xff08;一&#xff…

一篇教你学会Ansible

前言 Ansible首次发布于2012年&#xff0c;是一款基于Python开发的自动化运维工具&#xff0c;核心是通过ssh将命令发送执行&#xff0c;它可以帮助管理员在多服务器上进行配置管理和部署。它的工作形式依托模块实现&#xff0c;自己没有批量部署的能力。真正具备批量部署的是…

生产管理中,如何做好生产进度控制?

在生产管理中&#xff0c;我们常常会遇到以下问题&#xff1a; 由于计划不清或者无计划&#xff0c;导致物料进度无法保障&#xff0c;经常出现停工待料的情况。 停工待料导致了生产时间不足&#xff0c;为了赶交货期&#xff0c;只能加班加点。 生产计划并未发挥实际作用&am…

14、Python -- 列表推导式(for表达式)与控制循环

目录 for表达式&#xff08;列表推导式&#xff09;列表推导式的说明使用break跳出循环使用continue忽略本次循环使用return结束函数 列表推导式 使用break跳出循环 使用continue忽略本次循环 for表达式&#xff08;列表推导式&#xff09; for表达式用于利用其他区间、元组、…

哪些车企是前向雷达大客户?国产突围/4D升级进展如何

可穿透尘雾、雨雪、不受恶劣天气影响&#xff0c;唯一能够“全天候全天时”工作&#xff0c;同时在中远距离的物体识别能力&#xff0c;毫米波雷达成为二十几年前豪华车ACC功能的必备传感器。 此后&#xff0c;随着视觉感知技术的不断成熟&#xff0c;尤其是Mobileye、特斯拉等…

强化学习代码实战(3) --- 寻找真我

前言 本文内容来自于南京大学郭宪老师在博文视点学院录制的视频&#xff0c;课程仅9元地址&#xff0c;配套书籍为深入浅出强化学习 编程实战 郭宪地址。 正文 我们发现多臂赌博机执行一个动作之后&#xff0c;无论是选择摇臂1&#xff0c;摇臂2&#xff0c;还是摇臂3之后都会返…

MySQL Join 类型

文章目录 1 Join 类型有哪些2 Inner Join3 Left Join4 Right Join5 Full Join 1 Join 类型有哪些 SQL Join 类型的区别 Inner Join: 左,右表都有的数据Left Join: 左表返回所有的行, 右表没有的补充为 NULLRight Loin: 右表返回所有的行, 左表没有的补充为 NULLFull Outer J…

【会员管理系统】篇二之项目搭建、初始化、安装第三方库

一、项目搭建 1.全局安装vue-cli npm install -g vue/cli查看版本信息 vue -V 2.创建项目 vue create 项目名称 回车 回车 剩余选择如下 之后等待项目创建 最后npm run serve 二、初始化配置 1.更改标题 打开public下的index&#xff0c;将title标签里的改成想要设置的…