目录

内容摘要

进程的概念

进程管理

Linux下启动多个进程,那么Linux受否要进行进程管理呢?

既然需要进行进程管理,那么Linux操作系统是如何进行进程管理的呢?

管理的具体方式

进程组织

PCB

查看进程

通过ps方式进行查看

通过具体文件进行查看

通过top方式进行产看

通过系统调用获取进程

获取进程的pid、ppid接口函数

初识fork函数

认识for函数

fork函数的基本用法

为什么给父进程返回子进程的id,给子进程返回0?

fork函数为什么会有两个返回值?

父进程和子进程哪个会先进行运行?


内容摘要

本文内容包括进程概念其中对于进程管理、进程组织、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一次性执行完毕时,此时子进程先运行完。
 

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐