【Linux】进程的概念
本文内容包括进程概念其中对于进程管理、进程组织、PCB进行详细介绍,三种查看进程的方式即通过ps命令进行查看、通过具体文件进行查看、通过top命令进行查看,通过系统调用接口进行进程的查看,初步认识fork函数。
目录
Linux下启动多个进程,那么Linux受否要进行进程管理呢?
既然需要进行进程管理,那么Linux操作系统是如何进行进程管理的呢?
内容摘要
本文内容包括进程概念其中对于进程管理、进程组织、PCB进行详细介绍,三种查看进程的方式即通过ps命令进行查看、通过具体文件进行查看、通过top命令进行查看,通过系统调用接口进行进程的查看,初步认识fork函数。
进程的概念
主观认识
当我们从计算机中打开一个程序,程序会从磁盘中加载到内存中,这个过程本质就是启动了一个进程,在Linux下我同进行输入的命令 ./XXXX 也是启动了一个进程,Linux下也可以进行启动多个进程。
客观认识
进程=对应的代码和数据+PCB结构体(通过下面进程管理的分析就可以理解)
为什么每个对应的代码数据都有一个PCB结构体呢?PCB到底是个什么东东呢?我们继续往下看
进程管理
-
Linux下启动多个进程,那么Linux受否要进行进程管理呢?
答案是当然需要
-
既然需要进行进程管理,那么Linux操作系统是如何进行进程管理的呢?
还是那六字真言,先描述后组织
管理的具体方式
磁盘中的程序进行加载到内存中,程序加载到进行内存中就被称为进程,进程被加载到内存中,操作系统需要将这些进程进行管理(例如哪个进程需要被杀掉,哪个进程需要被重新加载到内存中等等),通过结构体对进程进行管理,在Linux下这个结构体称为PCB。
进程组织
CPU通过数据结构将每个task_sruct进行组织起来,通过对于数据结构的增删改查从而进行进程的管理。
知识串联:如何看待一切皆对象的思想
我们人是通过属性进行认识事物的,属性就是通过结构体对于数据或者对象进行描述,这不就是我们面向对象语言中的对象吗!
PCB
PCB(Process Control Block)指的是进程控制块,是操作系统用于追踪和管理每个进程的关键结构,Linux下结构体对于数据进行描述,这个结构体在Linux下是task_struct,tast_struct就是实现PCB的重要数据结构
注:结构体也是一种数据结构哦。
- 既然task_stuct是用来描述进程,那么都是从哪些方面进行进程描述的呢
task_ struct内容分类
- 标示符: 描述本进程的唯一标示符,用来区别其他进程。
- 状态: 任务状态,退出代码,退出信号等。
- 优先级: 相对于其他进程的优先级。
- 程序计数器: 程序中即将被执行的下一条指令的地址。
- 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
- 上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。
- I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
- 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等
进程的管理和组指我们都已将学习完了,那么进程的查看又是怎样的呢?我们接着往下看
查看进程
-
通过ps方式进行查看
命令 ps axj | grep 文件名
ps ajx | head -1 && ps axj | grep 相对于上一条命令增加了进程的属性字段
其中 ps axj 表示查看系统中的所有进程,ps axj | grep 文件名通过管道的方式进行过滤到我们想查看的特定进程。
右边是我为了方便进行进程的产看,写的一个死循环的程序,左边是将服务器复制进行进程的查看。
-
通过具体文件进行查看
命令ls /proc
proc是存放内存级进程的文件
-
通过top方式进行产看
这种方式相当于window系统下的任务管理器,产看进程的排序一般是按照占用内存的多少进行排序
通过系统调用获取进程
pid和ppid
想要直接进行获取进程的pid是不可行的,因为操作系统默认是不相信任何人的,我们只能通过系统接口进行调用相对应的函数来及逆行获取进程的pid。
-
获取进程的pid、ppid接口函数
getpid()
通过main手册进行查看接口函数的用法
man 2 getpid 其中2号手册用于专门查看系统接口
当我们进行查找2号手册可能出现如下报错
不要慌张,这是因为man手册的man-pages 安装包没有进行安装的缘故,执行下面这条命令即可。
yum install man-pages
通过阅读手册
- 函数getpid和函数getppid 的返回值都是 pid_t类型
- 函数的头文件 #include<sys/types.h> 或者 #include<unistd.h>
- 函数的返回值 对于getpid函数来说返回值是进程的id(这里通常被认为是唯一id) 对于getpid函数来说返回父进程的id
这里难免心生疑惑:test程序的pid我知道是我这个程序本事,那么ppid是谁呢?
我们通过查看进程命令进行查看父进程,发现test程序的父进程是base,在进行查看base的父进程,依次进行向上查看结果如上图所示。
初识fork函数
认识for函数
查看man手册
man 2 fork
- 函数功能:fork函数复制调用进程从而创建一个新的进程,这个新的进程作为子项,进行复制进程的这个称为父项
- 头文件:#include<unistd.h>
- 函数返回值类型:pid_t
- 函数的返回值:父进程返回子进程ID,子进程返回0,出错在父进程返回-1
父进程创建子进程
通过代码进行验证,确实进程的pid为25994的进程通过fork函数中,创建了一个子进程,其pid为25995,其父进程的pid为25994正好和父进程的pid正好契合。
-
fork函数的基本用法
当我们这个test.cpp运行后就是一个进程,代码开始从头开始执行,当执行到fork函数后,有个新个进程被创建出来,这个新被创建的进程称为子进程,进行创建子进程的进程称为父进程,这时候代码中是有两个执行流的,父进程的执行流和子进程的执行流分别进行执行后续代码,也就是说fork函数后代码是共享的。fork函数后是有两个执行流,本来只有一个执行流去完成任务,现在有两个执行流去执行,这是非常nice的,但是我们要的不是两个执行流去执行相同的代码,而是期望用不同的执行流去执行不同的代码。
在单执行流时if语句中只要满足其中一个if的条件就不会去匹配其他的判断语句,但是多执行流就不一样了,fork函数的返回值有两个,说明id的值是有两个不同的值的,此时这两个不同的值是两个不同的执行流,因为是两个不同的执行流,所以才可以执行不同的if语句,所以我们才选择通过if语句就实现了子进程去执行子进程部分的代码,父进程去执行父进程部分的代码,实现了不同进程去执行不同的代码部分。
-
为什么给父进程返回子进程的id,给子进程返回0?
感性的认识
父进程:子进程=1:n,也就是说父进程和子进程的比率是一对多的关系,这与我们在生活中也非常相似,父亲给不同的孩子进行取名字,就是为了方便对孩子进行管控,不至于其中一个孩子犯错误后将所有的孩子全部叫过来,只需要通过通过犯错孩子的名字进行叫过来然后进行批评教育,这里父进程返回子进程id,也是为了方便父进程对于对于子进程的管控,例如需要杀掉某个子进程通过子进程的id即可做到,子进程返回0,是因为子进程的父进程是唯一的,需要进行找到子进程的父进程是非常容易的,因此只要通过返回0告诉子进程自己有没有被成功建立。
-
fork函数为什么会有两个返回值?
当进程被加载到内存中,CPU从运行队列中开始进行读取执行,当父进程被读取执行时,fork函数是系统调用的函数接口,fork函数开始执行,当fork函数进行创建子进程后将子进程继续加载到运行队列的尾部,这样随着CPU继续读取执行,当运行队列执行完成后,fork函数中的return语句执行了两次,因此有两个返回值。
父进程和子进程哪个会先进行运行?
答案是不一定。
还是如上图,当CPU执行进程时,有可能父进程一次就被执行完成,此时父进程比子进程先执行完毕;有可能出现父进程正在被CPU加载执行创建出子进程后,父进程由于在CPU中时间到了,然后被下下来重新加载到运行队列的尾部,当子进程被加载到CPU一次性执行完毕时,此时子进程先运行完。
更多推荐
所有评论(0)