进程概念(二)----- 理解进程

前言

该篇文章是基于 进程概念(一) 的后续 ,前篇文章主要是为讲述进程概念做了一些铺垫知识,而本篇文章着重对进程本身进行介绍。


1. 进程概念


上一篇文章在讲述冯诺依曼的时候,已经明确了,在该体系下,所有要被运行的程序,一定会先被加载到内存,进而由内存再与 cpu 进行交互!

所以,一个已经加载到内存中的程序(或 正在运行的程序),叫做进程

这跟我们开机是同理的,开机的本质,就是启动操作系统这个软件,而开机的过程计算机所做的工作无非就是,将外设中的操作系统加载到内存中,所以进程也是这个道理。


2. 理解进程

假设,磁盘中存储了一个名为 test(代码 + 数据) 的程序,而今天我们想要运行这个可执行程序,在冯诺依曼体系中,决定了该程序在被运行之前,一定是先被加载到内存当中的。

但是,一个操作系统,不仅仅只有这一个进程,它是可以同时运行多个进程的!有些进程可能是正在被运行的,有些在休眠等等。而面对各种各样的进程,那操作系统肯定是需要将它们进行管理的!

那么现在的问题是,操作系统如何管理的这些进程呢? ---- 先描述,再组织的思路

先通过面向对象的思想,将每一个进程的所有属性描述起来,而面对这些进程,无非就是新增一个进程,删除一个进程等操作,那么就需要再将这些已经描述起来的进程,通过某种数据结构组织起来。

所以,任何一个进程,在加载到内存的时候,形成真正的进程时,操作系统要先创建描述进程(属性) 的结构体对象 ---- PCB(process control block) ---- 也即进程控制块!

那么操作系统在创建描述进程的结构体时,是如何对进程进行描述的? ----- 这其实就跟我们自然生活中是相似的。我们在描述某一个人时,我们一定是说,xxx 叫啥,身高体型,单/双眼皮,什么发型,什么穿衣搭配等属性,甚至是 ta 的肖像画!

所以在描述一个人或事物时,我们一定是通过他们的属性进行描述的,我们也是通过属性去认识某一个人或事物的。

而今天我在描述某一个人物时,这个人是佛山的,幼年体弱多病,但后面拜陈华顺为师,习得一套咏春拳术,并且发挥到了极致,曾经一度响彻佛山等地区,当我描述到这里的时候,我甚至不需要说他叫什么,大家就已经知道我在说谁了!所以,只要属性足够多,那么这些属性的集合,就是我们要描述的目标对象!

所以操作系统怎么描述进程? ---- 本质就是将这个要描述的进程的一堆属性放在一起,合起来,它就叫做进程!所以 PCB 的本质就是属性的集合!

而操作系统是 c 语言写的,所以操作系统想要描述进程,只能用 struct 结构体 进行描述,所以 PCB 本质就是操作系统内定义的一个 struct 结构体类型!

那么进程里面都有哪些属性呢?(此处不展开详谈,后续文章会对进程的常见属性进行详细介绍)

struct PCB
{
	进程编号		// 为了让操作系统可以找到某一个进程
	进程的状态	// 标记着进程当前的运行状态
	优先级		// 同样在运行中的进程,谁先谁吗慢?
	....
	struct PCB* next;		// 相关的指针信息
}

在创建进程的时候,操作系统首先会先创建一个描述进程的结构体对象,并对其内部属性进行初始化,而刚刚也说了,一个进程要被运行,该进程的代码和数据也要被加载到内存当中!比如我们通过 c++ 写的代码,最后经过编译形成的可执行程序,这就是我们的代码+ 数据,而当我们要运行这个程序的时候,不仅仅要将 代码和数据 加载到内存中,同时要为这个进程创建一个进程的结构体对象!

故事时刻:在学校里,我要成为该学校的一名学生,并且在该学校上课!我不仅仅需要考上这个学校,同时,我的各种信息需要在学校的教务系统中存在(即被录用),这样我才可以称作这个学校的一名学生。而张三作为我朋友的身份,来到我学校参观,虽然他在我的学校里面,但是学校的教务系统中,并没有张三这名学生!因此判定他不是我们学校的学生。所以,进程也是如此!操作系统将进程的代码和数据加载到内存之后,还会为进程创建一个描述该进程的 进程控制块(pcb)。

所以什么是进程? ----- 只有代码和数据,并不能称为进程,而是 PCB + 代码和数据,这样的结合体,才能够称为进程!
即,进程 = 内核 PCB 数据结构对象 + 代码和数据 (而 PCB 就是描述这个进程的所有属性)

而既然 PCB 就是描述这个进程的所有属性,那么它就一定需要有一个指针信息,指向与该进程所匹配的代码和数据,这样才能够通过 PCB 找到该进程的所有代码和数据,然后交给 cpu 运行,这就完成了对一个进程的管理!

在该故事的另一方面,学校在对学生进行管理的时候,只需要在教务系统上,对学生的信息进行管理即可(比如学校要开除李四,并不需要找到他的人,只需要将其从教务系统中移除即可)。所以操作系统也是如此!在管理进程的时候,根本就不看这个进程的代码和数据,而是对这个进程的 PCB 进行管理!在对多个进程进行管理的时候,只需要在每个进程中多新增一个指针类型的链接属性,将每个进程组织起来,那么操作系统在管理这些进程的时候,就等同于对数据结构进行增删查改!

为了更好的理解,操作系统只针对 PCB 进行管理,而不是进程的代码和数据,下面再举一个例子。

在企业中,hr 为了筛选人才,会对投递该岗位的所有面试者进行筛选。但是,hr 并不需要对人本身进行筛选,ta 只需要对该面试者所投递的简历进行筛选,最终安排这些投递简历的人排队面试。而投递简历的人,也并不需要就真的在公司排队!而是简历在排队!当面试官想要考虑你的时候,自然会根据你简历中的指针字段(即电话)联系到你,安排你的面试。而类似这种简历与你本人分开进行管理的现象,就与操作系统对进程的管理是相似的,操作系统只需要对进程的 PCB 进行管理,只要有需要,它可以通过 PCB 中的指针字段,找到这个进程所对应的代码和数据!


3. linux中的PCB


上面的一切,只是讲述所有操作系统对待进程的管理的模式,具体思路就是上面那么做的。但是具体某一款操作系统在进程管理上可能都存在一定的差别。所以接下来就 linux 系统中的进程作进一步介绍。

在 linux 系统中,所谓的 PCB 叫做 task_struct ,里面包括了描述进程的所有属性。可以理解为 PCB 是所有操作系统对进程的统称,而 task_struct 则是 PCB 的其中一种!

task_ struct 内容分类:
标识符:  描述本进程的唯一标识符,用来区别其他进程。
状态:  任务状态,退出代码,退出信号等。
优先级:  相对于其他进程的优先级。
程序计数器:  程序中即将被执行的下一条指令的地址。(其作用就相当于进程运行了一段时间后,因为系统调度等原因,停止了对该进程的执行而后续回来继续执行的时候,需要知道上次执行到什么地方了。也好比我们看书,今天看完不想看了之后,会在此处做一下标记,方便后续继续向下观看)
内存指针:  包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针(比如记录了该进程所匹配的代码和数据的存储位置)
上下文数据:  进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。
I/O状态信息:  包括显示的I/O请求,分配给进程的 I/O 设备和被进程使用的文件列表。
记账信息:  可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。(保证系统调度的公平等)
其他信息

接下来,我们来见一见所谓的进程!

ps axj | head -1 && ps axj | grep test

PPID    PID   PGID    SID TTY       TPGID STAT   UID   TIME COMMAND
2724   4957   4957   2724 pts/0      4957 S+    1001   0:00 ./test
3711   4961   4960   3711 pts/1      4960 S+    1001   0:00 grep --color=auto test

// 而这其中的 PID 就是进程的唯一标识符

在这里插入图片描述

查看进程的方法还有如下

ls /proc
// 该目录是 linux 系统中动态运行的所有进程的相关信息

在这里插入图片描述

我们还可以证明一下刚刚的 test 进程运行之后,在系统中的 proc 中是真实存在的!

在这里插入图片描述

这里顺带解释一下,为什么我们过滤出来的进程会有两个,其中一个还是 grep …,虽然 grep 是一个过滤器工具,是一条指令来着,但它本质上也是一个可执行程序,而当程序运行进来,叫进程,所以当我们在执行 grep 这条指令的时候,等同于我们在运行 grep 这个进程,而 grep 后面也带着 test 这样的关键字,因此在过滤的时候,不仅有 test 自己的进程信息,还有执行 grep 时创建的进程的信息。


在这里插入图片描述

在进程的相关信息里,我们要着重关注两个属性,一个是 cwd(当前进程的工作目录),一个是 exe( PCB中的内存指针执向的可执行程序的信息)。其中的当前工作目录,就涉及到其它方面的知识。

你有没有想过一个问题,当你在 touch 一个文件的时候,你并没有指定文件要创建在哪,但是文件都会创建在你当前所在目录中。换一个说法,当你在调 C 语言中的 fopen 打开文件的时候 fopen("tmp.txt", "w"),也只是指明了文件名,并没有指明文件的所在路径!而当程序运行起来后,却可以精准的找到你指定的文件,并且打开它,最后对该文件进行读写。

---- 这是因为进程中存在一个属性,叫做 cwd ,它记录了当前进程的工作目录!因此 touch 也好,执行这条指令的时候,就如同一个进程,而每个进程的属性里面都会记录当前的工作目录,所以当你touch的时候,并不需要指定路径,也可以将文件创建在你当前所处的目录下!fopen 也是如此,编译完成后形成的可执行程序,一但允许,进程中就有 cwd 这个属性,在进程的层面上,进程看到的是 cwd/tmp.txt,所以才能够顺利的找到该文件!


由于篇幅问题,关于 linux 中的 task_struct 的内容属性,在后续文章会继续介绍,感兴趣的请移步。。。。。

如果感觉该篇文章给你带来了收获,可以 点赞👍 + 收藏⭐️ + 关注➕ 支持一下!

感谢各位观看!

  • 22
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值