进程介绍,如何管理进程(pcb),查看进程,/proc文件系统,cwd文件,pid/ppid,进程状态(宏观+linux下RSTXZ),僵尸进程,孤儿进程,守护/精灵进程

目录

进程

介绍

如何管理进程

pcb内部的常见属性

介绍

查看进程的指令

ps的各种选项

/proc(用文件的方式查看进程)

/proc

cwd文件

应用场景

结束进程 -- kill

标识符(无符号整数)

pid

ppid

示例(bash)

代码查看pid和ppid -- getpid()函数/getppid()

状态 

宏观下

运行态

阻塞态

挂起态

内存页面交换

linux下

介绍

R -- 运行态

S -- 可中断睡眠

s->t

示例(一直在运行的程序,状态却是s)

原因

解决

D -- 深度睡眠

引入

作用

T / t -- 暂停状态

示例

调试时

kill指令的选项

X -- 死亡状态

Z -- 僵尸状态

示例

孤儿进程

引入

解决 -- init进程

进程组

前台进程组

后台进程组

守护进程 / 精灵进程


进程

介绍

在windows下,当我们运行软件时,我们就可以在任务管理器中找到它

  • 我们可以看到界面上有进程两个字,说明运行起来的 (也就是加载到内存上的) 程序就是进程,进程是计算机程序的执行实例

  •  而在linux下,指令也是可执行程序,因此当我们输入指令,也就是运行了一个进程
  • 这个图上有这么多进程,说明进程可以多个一起运行,并且一个程序可以产生多个进程(比如我们多开游戏)
  • 并且在任务管理器中,进程占用的各种资源大小是不断在变化的,因此进程具有动态属性

如何管理进程

  • 这么多的进程,cpu会放任他们不管吗?
  • 不会的,所以需要管理
  • 而管理就是 -- 先描述,再组织

  • 首先明确,与人描述世界相同 -- 人认识世界是通过属性确认的
  • 比如说,苹果 -- 是红色的,是接近球体的,有果皮包被等等
  • 那么对于计算机来说,将进程分出不同的属性,就是认识和描述进程
  • 当然,在计算机中,这些属性都以数据的形式存在
  • 而为了及时拿到这些属性,就需要被存储,存储的形式就是结构体(可以存放不同类型的数据)
  • 这个存放进程属性的结构体有自己的名字 -- PCB(Process Control Block,进程控制块),在linux下该结构体叫task_struct
  • 通过链表就可以将这些结构体组织起来

  • 每个进程都有对应的代码,包括指令和数据,它被加载到内存中并执行
  • 所以完整的进程 = 该进程内核数据结构(PCB) + 该进程对应的在磁盘上的可执行程序
  • 当进程被创建时,可执行程序从磁盘加载到内存,并与PCB一起形成一个完整的进程

pcb内部的常见属性

介绍

ps axj指令可以显示当前系统上运行的进程的信息:

其中,每一列代表了:

查看进程的指令

ps的各种选项

/proc(用文件的方式查看进程)

/proc
  • 是Linux操作系统中的一个特殊文件系统
  • 它不是一个常规的磁盘文件系统,而是一个内核信息虚拟文件系统
  • 里面的文件实际上并不存储在磁盘上,而是由内核动态生成的
  • 它提供了对正在运行的内核和系统信息的访问接口,以及有关系统和进程的各种详细信息
  •  进入其中一个进程后所有的文件:

cwd文件

大部分进程都有自己的cwd文件,记录的是自己的工作目录

这是cwd的文件属性:

应用场景
  • fopen函数中,在填写文件名时,如果不指定路径,就默认在当前目录下操作
  • 但是它是怎么知道自己的目录在哪呢?
  • 就是通过该cwd文件打开的

结束进程 -- kill

kill命令用于向进程发送信号的Unix和Linux命令

常用 kill -9 + 进程pid

来源 -- (26条消息) CentOS查看进程、杀死进程、启动进程等常用命令_centos7 查看/home占用进程_老友记茶舍的博客-CSDN博客

标识符(无符号整数)

pid

  • 操作系统中用于 唯一标识 每个正在运行的进程的数字标识符
  • 通过pid,操作系统和用户可以唯一标识、管理和控制每个运行的进程
  • pid范围通常从1开始1号进程是系统初始化进程,通常是init或systemd,它在系统启动时启动并管理其他进程

ppid

  • 是指某进程的父进程的进程id
  • 在操作系统中,每个进程都有一个父进程,除了初始化进程(就是上面说到的那个)之外
  • 当一个进程被创建时,它会继承创建它的进程的进程 id 作为它的 ppid
  • 每个进程都可以创建子进程,并成为新子进程的父进程
示例(bash)
  • 因此当我们在bash中执行指令时,bash 会创建新的子进程来运行这些命令
  • 在这种情况下,bash 将成为这些新子进程的父进程(可以看到,我们运行的ps指令,它的ppid就是bash的pid 26259):
  • 如果将bash杀掉,就无法进行命令行输入(每一次xshell登录运行的时候,都会分配一个新的bash)

代码查看pid和ppid -- getpid()函数/getppid()

头文件:<unistd.h>

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
 printf("pid: %d\n", getpid());
 printf("ppid: %d\n", getppid());
 return 0;
}

状态 

宏观下

运行态
它表明 进程要么是在运行中 , 要么运行队列里排队(等待cpu)
阻塞态
  • 系统中不只有cpu一种资源(磁盘,网卡,显卡等等都是),因此队列也不只有一种
  • 如果该进程需要使用的 非cpu资源 现在被占用,进程会进入该资源的队列中等待
  • 该队列就叫做阻塞队列,此时的状态就叫阻塞状态,是一种临时状态
  • 等待的资源就绪的时候,该进程就进入运行队列(可能会直接插队)
挂起态
  • 将进程或线程的执行暂时中止,以便稍后再恢复它们的执行,挂起是更持久的状态
  • 挂起进程处于非活动状态,不占用CPU时间片,并且被放置在后台等待特定的命令或事件唤醒
  • 阻塞和挂起并不冲突
内存页面交换

当系统的内存资源紧张时,操作系统可能会将部分不活动的内存页面交换到磁盘上,以释放内存供其他进程使用

  • 是一种操作系统的内存管理策略,旨在优化系统的性能和资源利用率
  • 磁盘中有一块区域,叫做swap区域
  • 内存不足但 仍在新运行程序 时,os会将 长时间不执行 / 需要很长时间来等待资源代码和数据 换出到 磁盘上的swap区域,该进程只剩下pcb
  • 当内存足够时,就会将swap区域中的代码和数据重新加载到内存上

linux下

介绍

这是内核中对于进程状态的定义数组:

R -- 运行态

也就是上面的宏观下的运行态 

S -- 可中断睡眠

对应上面的阻塞态,也被叫做可中断睡眠(可以被唤醒 -> 转换为其他状态)

s->t

eg: kill -19 + 进程pid ,可以让他从S状态变为T状态

示例(一直在运行的程序,状态却是s)

eg : 这样的代码,运行后查看进程状态:

  • 虽然它在不断打印,但可以看到进程状态是S耶,为什么捏?
  • 进程我们看着是一直在运行的,但显示出来进程一直在等待资源
原因
  • 因为有printf的参与
  • 显示器是外设,外设的访问速度比起cpu来说非常非常慢,所以向显示器打印可能需要进行一定时间的等待
  • 当外设资源就绪后,进程放入运行队列后,只经过了非常非常短的时间 ,就又需要等待资源了
  • 所以我们看到的状态基本都是S
解决

将printf语句去掉后,就可以看到其一直处于R状态

D -- 深度睡眠

也叫做睡眠状态/磁盘睡眠/深度睡眠(不可以 被动 唤醒)

引入
  • 进程在等待磁盘io时,需要长时间等待[写入完成的信号] (因为两者速度差距很大,但是又得给进程返回是否成功写入的信息) 
  • 如果此时系统内存不够用,os会通过一定手段将该进程杀掉,以节省空间
  • 但如果像这样直接被杀掉,写入过程就失败了,那传输的数据就有可能丢失
  • 那么这样的损失谁来承担呢?
  • 所以将该进程设置为 不可被唤醒的D状态

  • 当我们需要它醒来该怎么办呢?
  • 只能让进程自己醒来
  • (一般很难看到D状态的进程,但dd命令可以演示D状态 -- 还没去实现)
作用
  • 可以提高系统效率,因为D状态下的进程不会消耗CPU时间来等待数据就绪
  • 提高了进程的稳定性
T / t -- 暂停状态

本身并没有在等待资源,只是被暂停了

示例

例如下面不断循环打印的程序code,其pid是29534:

可以通过kill指令-19暂停进程:

调试时

从断点处停下来后,该进程就处于 t 状态 

(似乎t和T没啥区别,反正都是暂停状态)

kill指令的选项

不同编号对应不同的信号:

kill指令-18继续进程:

X -- 死亡状态

终止(死亡)状态,意味着可以被os回收资源啦

很难看到该状态,是瞬时性的事

Z -- 僵尸状态

终止状态的前一个状态

  • 为什么要有这样一个状态呢?
  • 类比一下,当有一个人确定死亡的时候,需要有法医来鉴定这个人是怎么死的
  • 万一是谋杀需要去调查的捏,当调查清楚后,就可以通知家属辽

说回计算机:

  • 当一个进程终止时,它通常会向其父进程发送一个终止信号,这个终止信号包含了退出状态信息,父进程可以使用wait()或waitpid()系统调用来获取这个信息
  • 父进程拿到子进程的终止状态后,由os清理其子进程的资源

  • 但是,如果父进程没有对子进程的退出进行处理,那么子进程就会处于僵尸状态 -- 一个进程已经退出,但还不允许被os释放,处于需要被父进程 / os 检测的一个状态
  • 子进程会保存自己的退出信息
  • 退出信息本身就是数据,也属于进程基本信息,所以保存task_struct(PCB)中
  • 换句话说,如果一个进程一直处于Z状态,进程一直不退出,PCB就一直都要维护这就会导致资源泄露
示例
  • 当子进程退出后,父进程处于睡眠状态,无法获取到子进程的退出信息时,此时子进程处于僵尸状态
  • 但是当父进程结束睡眠,即可释放子进程

孤儿进程

引入
  • 前面的僵尸进程是其父进程尚未回收(收集)子进程的终止状态和资源
  • 僵尸状态通常是暂时的,一旦父进程回收了子进程,僵尸进程会被清除
  • 如果父进程先退出导致子进程成为没有父进程的进程,就称之为“孤儿进程”
  • 它没有父进程读取它的退出信息+回收辽
  • 也就是说,如果不处理孤儿进程这个情况,是绝对会资源泄漏的
解决 -- init进程

为了解决这个问题,就规定孤儿进程被1号init进程领养,之后就由init进程接管它喽

我们可以看到,被init接管的孤儿进程,状态从S+变为了S:

这是什么意思呢?

进程组
  • 在Linux终端中,可以同时运行多个进程,并将它们分为不同的进程组
  • 当在终端中运行一个程序时,该程序及其子进程会被分配到一个进程组中
前台进程组
  • 通常情况下,前台进程组与终端交互的活动进程组
  • 它接收来自终端的输入并将输出发送到终端
后台进程组
  • 是在后台运行的进程组,它们不会接收来自终端的输入
  • 因此ctrl + c对这样的程序不起作用,可以使用kill指令发送信号给他

守护进程 / 精灵进程

这两种是同一种进程的不同翻译,是特殊的孤儿进程

  • 不但运行在后台,最主要的是脱离了与终端和登录会话的所有联系
  • 也就是默默的运行在后台不想受到任何影响

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值