Linux 进程基础概念-进程状态、进程构成、进程控制

Linux 进程

参考:

  • 「linux操作系统」进程的切换与控制·到底有啥关系? - 知乎 (zhihu.com),Linux进程解析_deep_explore的博客-CSDN博客,腾讯面试:进程的那些数据结构 - 知乎 (zhihu.com),如何在Linux下的进行多进程编程(初步) - 知乎 (zhihu.com),彻底搞定面试官,linux的进程里面的一些细节 - 知乎 (zhihu.com),操作系统进程的概念,进程的状态及状态转换,进程控制程小智的博客-CSDN博客进程的状态及其转换。

  • Linux 进程详解 - 程序员大本营 (pianshen.com)。Linux进程基础教程详解Linux脚本之家 (jb51.net)。

  • 【Linux】Linux进程的创建与管理Yngz_Miao的博客-CSDN博客linux 创建进程。

  • 《Linux System Prorgrammin》,Linux系统编程 _ 中文版 _ by _ 哈工大(翻译)-第五章-进程管理。

  • Linux 操作系统 C 语言编程入门。

进程基础概念

程序与进程

通俗的讲程序是一个包含可以执行代码的文件,是一个静态的文件。而进程是一个开始执行但是还没有结束的程序的实例。就是可执行文 件的具体实现。一个程序可能有许多进程,而每一个进程又可以有许多子进程。

进程状态

  1. 创建态:进程正在被创建,尚未转到就绪态。

  2. 就绪态:进程获得了除处理机以外的一切所需资源,一旦得到处理机便可立即运行。

    • 状态特点:处理机(或者理解为调度器)资源:只缺处理机。资源获得:已获得所需资源。当获得处理机时:立即运行。

    • 状态转换:就绪态——>运行态:处于就绪态的进程被调度后,获得处理机资源,于是进程由就绪态切换为运行态。

  3. 运行态:进程正在处理机上运行;对于单处理机,同一时刻只有一个进程处于运行态。

    • 状态转换:运行态——>就绪态:情况1:处于运行态的进程在时间片用完后,不得不让出处理机,进而转换为就绪态。情况2:在可剥夺的操作系统中,当有更高优先级的进程就绪时,调度程序将正在执行的进程转换为就绪态,让更高优先级的进程执行。

    • 状态转换:运行态——>阻塞态(主动行为):进程请求某一资源(如外设)的使用或等待某一事件的发生(如I/O操作的完成)时,它就从运行态转换为阻塞态。进程以系统调用的形式请求操作系统提供服务,这是一种特殊的,由用户态程序调用操作系统内核过程的形式。

  4. 阻塞态:又称等待态,进程正在等待某一事件而暂停运行/休眠,如等待某资源或IO完成,即使处理机空闲,该进程也不能运行。

    • 状态特点:处理机(或者理解为调度器)资源:可能缺;也可能不缺。资源获得:等待某资源可用或等待一件事情完成。当获得处理机时:即使处理机空闲,当等待的事情没有完成,仍无法运行。

    • 状态转换:阻塞态——>就绪态(被动行为,需要其他相关进程的协助):进程等待的事件到来,如I/O操作结束或中断结束时,中断处理程序必须把相应进程的状态由阻塞态转换为就绪态。

  5. 终止态:进程正从系统中消失,可能是进程正常结束或其他原因退出运行。

对应到 Linux 内核中,各个进程状态的标志:

  • TASK_RUNNING 说明进程已经准备好了,就看操作系统给不给分时间片在 CPU 上执行了,进程获得了时间片,就是执行状态,不分配时间片就是就绪状态。代表状态的字段又不用变。

    • 其实 TASK_RUNING 这个字段既对应了进程的就绪态又对应了进程的运行态。

    • 只有在该状态的进程才可能在 CPU上运行。而同 一时刻可能有多个进程处于可执行状态,这些进程的 task_struct结构(进程控制块)被放入对应 CPU的可执行队列中(一个进程最多只能出现在一个 CPU的可执行队列中)。进程调度器的任务就是从各个 CPU的可执行队列中分别选择一个进程在该 CPU 上运行。

    • 只要可执行队列不为空,其对应的 CPU就不能偷懒,就要执行其中某个进程。一般称此时的 CPU“忙碌”。对应的, CPU“空闲”就是指其对应的可执行队列为空,以致于 CPU无事可做。

    • 很多操作系统教科书将正在 CPU上执行的进程定义为 RUNNING状态、而将可执行但是尚未被调度执行的进程定义为 READY状态,这两种状态在 linux下统一为 TASK_RUNNING状态。

  • TASK_INTERRUPTIBLETASK_UNINTERRUPTIBLE 是两种睡眠状态,对应上面的阻塞状态。TASK_INTERRUPTIBLE 可以再被信号唤醒,TASK_UNINTERRUPTIBLE 不可被信号唤醒。

    • TASK_INTERRUPTIBLE,可中断的睡眠状态。处于这个状态的进程因为等待某某事件的发生(比如等待 socket连接、等待信号量),而被挂起。这些进程的 task_struct结构被放入对应事件的等待队列中。当这些事件发生时(由外部中断触发、或由其他 进程触发),对应的等待队列中的一个或多个进程将被唤醒。通过 ps命令我们会看到,一般情况下,进程列表中的绝大多数进程都处于 TASK_INTERRUPTIBLE状态(除非机器的负载很高)。

    • TASK_UNINTERRUPTIBLE,不可中断的睡眠状态。与 TASK_INTERRUPTIBLE状态类似,进程处于睡眠状态,但是此刻进程是不可中断的。不可中断,指的并不是 CPU不响应外部硬件的中断,而是指进程不响应异步信号。即 kill -9 无法 关掉/杀死 这种进程。TASK_UNINTERRUPTIBLE 状态存在的意义就在于,内核的某些处理流程是不能被打断的。如果响应异步信号,程序的执行流程中就会被插入一段用于处理异步信号的流程(这个插入的流程可能只存在于内核态,也可能延伸到用户态),于是原有的流程就被中断了。

      在进程对某些硬件进行操作时(比如进程调用 read 系统调用对某个设备文件进行读操作,而 read 系统调用最终执行到对应设备驱动的代码,并与对应的物 理设备进行交互),可能需要使用 TASK_UNINTERRUPTIBLE 状态对进程进行保护,以避免进程与设备交互的过程被打断,造成设备陷入不可控的 状态。这种情况下的 TASK_UNINTERRUPTIBLE 状态总是非常短暂的,通过 ps 命令基本上不可能捕捉到。Linux系统中也存在容易捕捉的 TASK_UNINTERRUPTIBLE状态。执行 vfork系统调用后,父进程将进入TASK_UNINTERRUPTIBLE状态,直到子进程调用 exit或 exec。

  • TASK_STOPPED 是在进程收到 SIGSTOP 以及 SIGTTIN 等信号的状态,你 Linux 进程运行起来按 Ctrl + z 后进程就是这个状态。

    • 向进程 发送一个 SIGSTOP信号,它就会因响应该信号而进入 TASK_STOPPED状态(除非该进程本身处于 TASK_UNINTERRUPTIBLE状态而不响应信号)。( SIGSTOP与 SIGKILL信号一样,是非常强制的。不允许用户进程通过 signal系列的系统调用重新设置对应的信号处理函数。)

    • 向进程发送一个 SIGCONT信号,可以让其从 TASK_STOPPED状态恢复到 TASK_RUNNING状态。

  • TASK_TRACED 是进程被监视的状态。

    • 当进程正在被跟踪时,它处于 TASK_TRACED这个特殊的状态。“正在被跟踪”指的是进程暂停下来,等待跟踪它的进程对它进行操作。比如在 gdb中 对被跟踪的进程下一个断点,进程在断点处停下来的时候就处于 TASK_TRACED状态。而在其他时候,被跟踪的进程还是处于前面提到的那些状态。

    • TASK_STOPPED和 TASK_TRACED状态判断。对于进程本身来说, TASK_STOPPED和 TASK_TRACED状态很类似,都是表示进程暂停下来。而 TASK_TRACED状态相当于在 TASK_STOPPED之上多了一层保护,处于 TASK_TRACED状态的进程不能响应 SIGCONT信号而 被唤醒。只能等到调试进程通过 ptrace系统调用执行 PTRACE_CONT、 PTRACE_DETACH等操作(通过 ptrace系统调用的参数指定 操作),或调试进程退出,被调试的进程才能恢复 TASK_RUNNING状态。

  • TASK_DEAD - EXIT_ZOMBIE,退出状态,进程成为僵尸进程。EXIT_DEAD 是最终状态,进入这个状态代表进程要从系统中删除了EXIT_ZOMBIEEXIT_DEAD 的前一个状态,这个时候进程已经终止,但父进程还没有用 wait() 等系统调用来获取他的终止信息,这个状态的进程叫做僵尸进程。这个状态 kill 命令是杀不死的,你们可以想以下应该怎样清楚僵尸进程,以及怎样避免僵尸进程的存在。

    关于 退出 相关的 进程状态(上面四个),更多可详见  Linux进程解析_deep_explore的博客-CSDN博客。

Linux 进程状态转换示意图:

系统进程常见的 STAT 代码:

就绪队列与阻塞队列:

就绪队列:系统中处于就绪状态的进程可能有多个,通常把它们排成一个队列。只要就绪队列不空,CPU就总是可以调度进程运行,保持繁忙,这与就绪进程的数目没有关系;除非就绪队列为空,此时CPU进入等待态,CPU效率下降。

阻塞队列:系统通常将处于阻塞态的进程也排成一个队列,甚至根据阻塞原因不同,设置多个阻塞队列。

进程的构成

引自 进程的那些数据结构 - 知乎 (zhihu.com),Linux下的task_struct结构体 - 百度文库 (baidu.com)。

进程一般由以下几个部分组成:

  • 进程控制块(PCB):每个进程在创建时, 系统都会为进程创建一个相应的 PCB。PCB 是进程存在的唯一标志。

    • 创建进程实质就是创建进程的 PCB。PCB 要能展示进程身份和关系,标记任务状态,标记权限,帮助任务调度等等。

    • Linux 内核中是把进程和线程统一当作任务来实现的,Linux 内核的 进程控制块 是 task_struct 结构体,里面包含有:

      • The identifier of the process (a process identifier , or PID) ;(进程的标识自身的唯一标识符 PID)

      • Register values for the process including, notably, the program counter and stack pointer values for the process;(进程调度时候退出时间片(保存现场)与进入时间片(恢复现场)时候用到的寄存器值包括栈指针 SP、程序计数器 PC 等等)

      • The address space for the process;(进程的地址空间)

      • Priority (in which higher priority process gets first preference. eg., nice value on Unix operating systems);(优先级)

      • Process accounting information, such as when the process was last run, how much CPU time it has accumulated, etc;

      • Pointer to the next PCB i.e. pointer to the PCB of the next process to run;

      • I/O Information (i.e. I/O devices allocated to this process, list of opened files, etc).

    • pid_t pid;    // 展示自己进程的 id
      pid_t tgid;  // 进程主线程的id
      struct task_struct *group_leader;  // 指向主线程地址

      每个进程都会创建一个主线程,所以如果只是单独一个进程,以及进程默认创建的主线程,那么 pidtgid 都会是自己。如果是一个进程创建的子线程,那么 pid 就是自己的 idtgid 就指向进程主线程的 id。

    • struct task_struct __rcu * real_parent;
      struct task_struct __rcu * parent;   // 指向父进程
      struct list_head children;   // 父进程的所有子进程都在子进程链表中,这里指向链表的头部。
      struct list_head sibling;  // 连接兄弟进程

      进程是一个树状的结构(使用链表组成的树),除了 0 号进程外,所有的进程都是由父进程创建的,所以对父进程的操作很容易就会影响到子进程。所以进程的数据结构中自然要显示出进程有哪些父子进程以及兄弟进程。

  • 程序段:程序段是进程中能被进程调度程序调度到 CPU 上执行的程序代码段。

  • 数据段:可以是进程对应程序加工的原始数据,也可以是程序执行时产生的中间 结果或结果数据。

进程控制

进程控制的主要功能是对系统中的所有进程实施有效的管理,它具有创建新进程、撤销已有进程、实现进程状态转换等功能。简而言之,进程控制就是为了实现进程状态转换。

一般 进程控制 的 程序段 是 “原子操作” 的,执行过程 期间不允许被中断;它使用 “关中断指令” 和 “开中断指令” 这两个特权指令实现原子性。

进程创建和终止

进程控制之进程创建和终止 相关的概念。

引起进程创建的事件

  • 用户登陆:分时系统中,用户登陆成功,系统会为其建立一个新的进程。

  • 作业调度:多道批处理系统中,有新的作业放入内存时,会为其建立一个新的进程。

  • 提供服务:用户向操作系统提出某些请求时,会新建一个进程处理该请求。启动程序执行都会创建一个新进程。

  • 应用请求:由用户进程主动请求创建一个子进程。

操作系统创建新进程的过程

  1. Step1:为新进程分配一个唯一的进程标识号,并申请一个空白PCB(PCB是有限的),若PCB申请失败,则创建失败。

  2. Step2:为进程分配所需资源,如文件、内存、I/O设备和CPU时间等。这些资源从操作系统获得,或从其父进程获得。如果资源不足(如内存),则此时并不是创建失败,而是处于创建态,等待内存资源。

  3. Step3:初始化PCB,主要包括初始化标志信息、初始化处理机状态信息和初始化处理机控制信息,以及设置进程的优先级等。

  4. Step4:若进程就绪队列能够接纳新进程,则将新进程插入就绪队列,等待被调度运行。

父进程创建子进程

允许一个进程创建另一个进程,此时创建者称为父进程,被创建的进程称为子进程。子进程可以继承父进程所拥有的资源;当子进程被撤销时,应将其从父进程那里获得的资源归还给父进程;当父进程被撤销时,通常也会同时撤销其所有的子进程。父进程和子进程共享一部分资源,但不能共享虚拟地址空间,在创建子进程时,会为子进程分配资源,如虚拟地址空间等。

父进程与子进程当然可以并发执行。进程控制块(PCB)是进程存在的唯一标志,每个进程都有自己的PCB。父进程与子进程不能同时使用同一临界资源,临界资源一次只能被一个进程使用(临界资源就是加了锁机制,只能被互斥地访问)。

Linux 系统创建进程都是由已存在的进程创建的(除了0号进程),被创建的进程叫做子进程,创建子进程的进程就做父进程。Linux 进程串起来是一颗树的结构。

引起进程终止的事件

  • 正常结束:表示进程的任务已完成并准备退出运行。

  • 异常结束:表示进程在运行时,发生了某种异常事件,使程序无法继续运行,如存储区越界、保护错、非法指令、特权指令错、运行超时、算术运算错、I/O故障等。

  • 外界干预:指进程应外界的请求而终止运行,如操作员或操作系统干预、父进程请求和父进程终止。

操作系统终止进程的过程

  1. Step1:根据被终止进程的标识符(PID),检索出该进程的PCB,从中读出该进程的状态。

  2. Step2:若被终止的进程正处于运行态,应立即终止该进程的运行,将处理机资源分配给其他进程。

  3. Step3:若该进程还有子孙进程,则应当将其所有子孙进程终止。

  4. Step4:将该进程所拥有的全部资源,或归还给其父进程,或归还给操作系统。

  5. Step5:该PCB从所在队列中删除。

查看和释义各个进程

我们在 Linux 系统上通过 ps - ef 命令查看系统目前的进程。

  • UID 就是用户的标识符(通过 root 用户创建的进程 UID 就是 root,如果我自己创建的话就应该是我的用户名。

  • PID 就表示的是当前进程的 id。

  • PPID 就表示当前进程的父进程 id。

通过 0 号进程创建 1 号进程和 2 号进程,然后通过 1 号进程去创建用户态进程,再通过 2 号进程创建内核态进程,就生成了 Linux 进程树。

  • 0号进程:在内核初始化的过程中,会先通过指令 struct task_struct init_task = INIT_TASK(init_task) 创建 0 号进程。这是唯一一个没有通过 fork 或者 kernel_thread 产生的进程。是进程列表的第一个。但是这个进程不是实际意义上的进程,类似与链表头。所以虽然 0 号进程是在内核态创建的,但不能说 0 号进程是内核态的第一个进程,反而要说 2 号进程是内核态的第一个进程。

  • 1号进程:通过调用指令 kernel_thread(kernel_init, NULL, CLONE_FS) 从内核态切换到用户态来创建的,1号进程是所有用户态的祖先。进程1也叫做init进程,它是内核初始化时创建的第2个内核线程,其运行代码为内核函数init()。只要系统不结束,init进程就永不中止,它负责创建和监控操作系统外层所有进程的活动。

  • 2号进程:通过调用指令 kernel_thread(kthreadd, NULL, ClONE_FS | CLONE_FILES) 来创建,2号进程负责所有内核态的进程的调度和管理,是内核态所有进程的祖先。(注意,内核态不区分线程和进程,所以说进程和线程都可以,都是任务)。

pstree 命令来显示整个进程树, Linux基础命令---显示进程树pstree_weixin_34023863的博客-CSDN博客。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

算法通过村第四关-栈黄金笔记|表达式问题

文章目录 前言1. 计算器问题2. 逆波兰表达式问题 总结 前言 提示:快乐的人没有过去,不快乐的人除了过去一无所有。 --理查德弗兰纳根《深入北方的小路》 栈的进阶来了,还记得栈的使用场景吗?表达式和符号,这不就来了 1…

【LeetCode-中等题】437. 路径总和 III

文章目录 题目方法一:迭代层序 每层节点dfs 维护一个count变量 题目 方法一:迭代层序 每层节点dfs 维护一个count变量 思路: 层序遍历每一个节点遍历一个节点就对这个节点进行dfsdfs的同时,维护一个count变量,并且…

ARDUINO STM32 SSD1306

STM32F103XX系列SPI接口位置 在ARUDINO 下,(不需要设置引脚功能,不需要开启时钟设置,ARDUINO已经帮我们处理了) stm32f103c6t6 flash不足,不足以运行U8G2,产生错误 改用U8X8,后将字体改为u8x8_…

Ubuntu 22.04安装 —— Win11 22H2

目录 Ubuntu使用下载UbuntuVmware 安装图示安装步骤图示 Ubuntu使用 系统环境: Windows 11 22H2Vmware 17 ProUbutun 22.04.3 Server Ubuntu Server documentation | Ubuntu 下载 Ubuntu 官网下载 建议安装长期支持版本 ——> 可以选择桌面版或服务器版(仅包…

基于侏儒猫鼬算法优化的BP神经网络(预测应用) - 附代码

基于侏儒猫鼬算法优化的BP神经网络(预测应用) - 附代码 文章目录 基于侏儒猫鼬算法优化的BP神经网络(预测应用) - 附代码1.数据介绍2.侏儒猫鼬优化BP神经网络2.1 BP神经网络参数设置2.2 侏儒猫鼬算法应用 4.测试结果:5…

基于JAVAEE技术的ssm校园车辆管理系统源码和论文

基于JAVAEE技术的ssm校园车辆管理系统源码和论文105 开发工具:idea 数据库mysql5.7 数据库链接工具:navcat,小海豚等 技术:ssm 1.选题背景和意义 背景: 随着第二次工业革命后,内燃机的发明与完善,解…

原生js实现轮播图及无缝滚动

我这里主要说轮播图和无缝滚动的实现思路,就采用最简单的轮播图了,当然实现的思路有很多种,我这也只是其中一种。 简单轮播图的大概结构是这样的,中间是图片,二边是箭头可以用来切换图片,下面的小圆点也可以…

three.js(九):内置的路径合成几何体

路径合成几何体 TubeGeometry 管道LatheGeometry 车削ExtrudeGeometry 挤压 TubeGeometry 管道 TubeGeometry(path : Curve, tubularSegments : Integer, radius : Float, radialSegments : Integer, closed : Boolean) path — Curve - 一个由基类Curve继承而来的3D路径。 De…

可控生成:ControlNet原理

🤗关注公众号funNLPer体验更佳阅读🤗 论文:Adding Conditional Control to Text-to-Image Diffusion Models 代码:lllyasviel/ControlNet 简单来说ControlNet希望通过输入额外条件来控制大型图像生成模型,使得图像生成模型根据可控。 文章目录 1. 动机2. ControlNet原理…

Hadoop依赖环境配置与安装部署

目录 什么是Hadoop?一、Hadoop依赖环境配置1.1 设置静态IP地址1.2 重启网络1.3 再克隆两台服务器1.4 修改主机名1.5 安装JDK1.6 配置环境变量1.7 关闭防火墙1.8 服务器之间互传资料1.9 做一个host印射1.10 免密传输 二、Hadoop安装部署2.1 解压hadoop的tar包2.2 切换…

让企业主们头疼的mkp勒索病毒,究竟有何来历,勒索病毒解密

mkp勒索病毒是一种比较常见的电脑病毒,它会对感染的电脑进行加密,并要求用户支付一定的赎金才能解锁。这种病毒已经引起了全球范围内的关注,因为它已经造成了严重的经济损失和电脑系统崩溃。 mkp勒索病毒是一种相对较新的病毒,但是…

集丰照明|汽车美容店设计,装修色彩灯光搭配方法

正确处理好店面的空间设计。 店铺各个功能区设计要合理,衔接合理,这样既能提高员工的工作效率也能提高顾客的满意度。合理安排店铺的空间分配, 要给顾客一种舒适度,既不能让顾客感觉到过于拥挤,又不能浪费店铺的有限空…

学习高级数据结构:探索平衡树与图的高级算法

文章目录 1. 平衡树:维护数据的平衡与高效性1.1 AVL 树:严格的平衡1.2 红黑树:近似平衡 2. 图的高级算法:建模复杂关系与优化2.1 最小生成树:寻找最优连接方式2.2 拓扑排序:解决依赖关系 拓展思考 &#x1…

【Unity】URP屏幕后处理UI模糊效果实现

这里Canvas(1)设置为Overlay能渲染出指定UI高清,其他UI模糊,然而这做法非常不好,如果此时再打开UI 以及 关闭模糊效果 要将这些置顶UI 恢复到原本Canvas里,也就是要管理2套Canvas using System; using System.Collections; using…

【仿写spring之ioc篇】二、bean生命周期中的创建以及属性赋值

扫描类 这个类就不多说了,基本所有框架都要有这一步,这里主要关注我们目前要实现的方法,其他的具体方法可以查看源码 isComponent方法 /*** 扫描所有带有Component注解的java类,放入到BeanRegistry** return boolean*/public bo…

以“迅”防“汛”!5G视频快线筑牢防汛“安全堤”

近期,西安多地突发山洪泥石流灾害。防洪救灾刻不容缓,为进一步做好防汛工作,加强防洪调度监管,切实保障群众的生命财产安全,当地政府管理部门亟需拓展智能化技术,通过人防技防双保障提升防灾救灾应急处置能…

无涯教程-Android - CheckBox函数

CheckBox是可以由用户切换的on/off开关。为用户提供一组互不排斥的可选选项时,应使用复选框。 CheckBox 复选框属性 以下是与CheckBox控件相关的重要属性。您可以查看Android官方文档以获取属性的完整列表以及可以在运行时更改这些属性的相关方法。 继承自 android.widget.T…

Git企业开发控制理论和实操-从入门到深入(六)|多人协作开发

前言 那么这里博主先安利一些干货满满的专栏了! 首先是博主的高质量博客的汇总,这个专栏里面的博客,都是博主最最用心写的一部分,干货满满,希望对大家有帮助。 高质量博客汇总 然后就是博主最近最花时间的一个专栏…

MTK6833_MT6833核心板_天玑700安卓5G核心板规格性能介绍

MTK6833安卓核心板采用台积电 7nm 制程的5G SoC,2*Cortex-A766*Cortex-A55架构,搭载Android12.0操作系统,主频最高达2.2GHz 。内置 5G 双载波聚合技术(2CC)及双 5G SIM 卡功能,实现优异的功耗表现及实时连网…

Watermark 是怎么生成和传递的?

分析&回答 Watermark 介绍 Watermark 本质是时间戳,与业务数据一样无差别地传递下去,目的是衡量事件时间的进度(通知 Flink 触发事件时间相关的操作,例如窗口)。 Watermark 是一个时间戳, 它表示小于该时间戳的…