当前位置:   article > 正文

【Linux】进程概念与进程状态_为什么linux 父进程id不变子进程id会改变

为什么linux 父进程id不变子进程id会改变

一、什么进程

1.进程概念

说到进程,书里经常给出简短的话对其解释:一个运行起来(加载到内存)的程序就是进程

那么为什么呢?在了解操作系统是如何实现进程管理之前,我们先来具体了解进程到底是什么

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pdXKxa5i-1670237895159)(C:\Users\DongYu\AppData\Roaming\Typora\typora-user-images\image-20221129191512219.png)]

由上篇博客我们已经知道,任何程序在运行时都需先加载到内存,CPU只与内存进行交互。假如我们现在写了一个程序,而程序的本质就是一个存放在磁盘上的文件。所以当我们要运行程序时,程序首先需要加载到内存中。

此时就有问题了


在加载这个文件时,此时会不会有其他文件也在加载中?那要先加载哪一个?同时许多程序在加载时,每个程序要给其调度多少资源?此时内存中已运行结束的程序缓存要不要清除?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yDLyj6hj-1670237895160)(C:\Users\DongYu\AppData\Roaming\Typora\typora-user-images\image-20221129192527669.png)]

此时此刻那叫一个手忙脚乱,因此我们的管理大师 — 操作系统说:”无所谓,我会出手“

操作系统管理的理念是什么? — 先描述,再组织

所以操作系统首先把所有的进程都描述起来,而为了描述每一个进程,就产生了PCB

2.描述进程-PCB

每个进程都有其属性,比如:加载的紧急程度、需要调用什么资源、占用多少空间…所以在管理进程时,操作系统会根据每个进程的需求去给其添加相应的属性,然后将其打包起来变成一个个”进程控制块“,又叫PCB

windows操作系统上,这些进程控制块直接称为PCB
而在linux操作系统中,这些进程控制块被命名为:task_struct

task_struct内容分类

  • 标示符: 描述本进程的唯一标示符,用来区别其他进程。
  • 状态: 任务状态,退出代码,退出信号等。
  • 优先级: 相对于其他进程的优先级。
  • 程序计数器: 程序中即将被执行的下一条指令的地址。
  • 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。
  • 上下文数据: 进程执行时处理器的寄存器中的数据。
  • I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
  • 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
  • 其他信息

3.组织进程

描述完之后,操作系统便利用数据结构对其进行组织。比如通过链表,将每个PCB链接起来

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ljOzIJUg-1670237895160)(C:\Users\DongYu\AppData\Roaming\Typora\typora-user-images\image-20221129194417155.png)]

所以到最后,所谓的进程管理,变成了对进程对应的PCB进行相关的管理,再通过数据结构转化为对链表的增删查改。

综上所述,准确来说
进程 = 内核数据结构(task_struct)+进程对应的磁盘代码

二、进程的基本操作

1.查看进程

✏️借助管道使用 ps axj 指令配合 grep 指令来查看指定进程

我们可以在Linux中写一段死循环的程序,便于我们查看进程

在这里插入图片描述

2.获取进程标识符

  • 进程id:pid
  • 父进程id:ppid
  • 获取进程id:getpid( )
  • 获取父进程id:getppid( )
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main()
{
    while(1)
     {
         printf("我是一个进程,我的id是:%d,我的父进程id是%d\n",getpid(),getppid());
         sleep(1);                                                                                                                                                                      
     }
     return 0;
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vKTzgNHr-1670237895161)(C:\Users\DongYu\AppData\Roaming\Typora\typora-user-images\image-20221201165024214.png)]

❓当我们中止进程再重新加载,id又会是什么呢?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CZFvy8LH-1670237895161)(C:\Users\DongYu\AppData\Roaming\Typora\typora-user-images\image-20221201165412289.png)]

由图我们可以发现,当我们重新运行程序时,此程序进程的id会与之前不同。因为重新运行也即是重新从磁盘中加载到内存,所以进程的id便会改变。但是我们发现它的父进程id是不变的?那到底是谁来产生的子进程呢?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BOQX4IVn-1670237895161)(C:\Users\DongYu\AppData\Roaming\Typora\typora-user-images\image-20221201165946457.png)]

通过具体查看进程,我们发现,test程序的父进程是bashbash也即是shell外壳。这也证明了在执行指令时,shell为了防止程序有误奔溃,导致自身奔溃,所以安全起见,在运行程序时,shell不会自己去执行指令,而是不断地去派生子进程去执行。所以这也是每个程序进程在不断重新运行时,其父进程保持不变的原因。

3.初识创建子进程

认识完子进程父进程,我们是否能够自己手动去创建子进程呢?系统调用接口提供了 fork 让我们实现这个目的

fork 在进程管理中能够起到许多作用,而我们目前作为初步认识进程管理,也不对fork进行过多展开,初识fork即可。

在Linux中我们可以通过指令 man 了解fork的用法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SGazIEQb-1670237895162)(C:\Users\DongYu\AppData\Roaming\Typora\typora-user-images\image-20221201171938625.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HJoqxuN2-1670237895162)(C:\Users\DongYu\AppData\Roaming\Typora\typora-user-images\image-20221201172055277.png)]

简而言之,fork能够创建子进程✏️我们通过代码验证一下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ievVoiwT-1670237895162)(C:\Users\DongYu\AppData\Roaming\Typora\typora-user-images\image-20221201173056612.png)]![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dl7zoafd-1670237895162)(C:\Users\DongYu\AppData\Roaming\Typora\typora-user-images\image-20221201173316074.png)](https://img-blog.csdnimg.cn/16f1e429a2e5408f8e1360bc1943317c.png

代码的运行结果发现,printf( )函数我们只写了一次,但是运行结果却调用了2次,正是因为fork执行创建了子进程后,会有两个进程去执行fork( )之后的代码

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/41757
推荐阅读
相关标签