赞
踩
说到进程,书里经常给出简短的话对其解释:一个运行起来(加载到内存)的程序就是进程
那么为什么呢?在了解操作系统是如何实现进程管理之前,我们先来具体了解进程到底是什么
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pdXKxa5i-1670237895159)(C:\Users\DongYu\AppData\Roaming\Typora\typora-user-images\image-20221129191512219.png)]](https://img-blog.csdnimg.cn/3a3f2b776fd54dff81d3a04eea81b1ea.png)
由上篇博客我们已经知道,任何程序在运行时都需先加载到内存,CPU只与内存进行交互。假如我们现在写了一个程序,而程序的本质就是一个存放在磁盘上的文件。所以当我们要运行程序时,程序首先需要加载到内存中。
此时就有问题了❓
在加载这个文件时,此时会不会有其他文件也在加载中?那要先加载哪一个?同时许多程序在加载时,每个程序要给其调度多少资源?此时内存中已运行结束的程序缓存要不要清除?…
此时此刻那叫一个手忙脚乱,因此我们的管理大师 — 操作系统说:”无所谓,我会出手“
操作系统管理的理念是什么? — 先描述,再组织
所以操作系统首先把所有的进程都描述起来,而为了描述每一个进程,就产生了PCB
每个进程都有其属性,比如:加载的紧急程度、需要调用什么资源、占用多少空间…所以在管理进程时,操作系统会根据每个进程的需求去给其添加相应的属性,然后将其打包起来变成一个个”进程控制块“,又叫PCB。
在windows操作系统上,这些进程控制块直接称为PCB
而在linux操作系统中,这些进程控制块被命名为:task_struct
task_struct内容分类
- 标示符: 描述本进程的唯一标示符,用来区别其他进程。
- 状态: 任务状态,退出代码,退出信号等。
- 优先级: 相对于其他进程的优先级。
- 程序计数器: 程序中即将被执行的下一条指令的地址。
- 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。
- 上下文数据: 进程执行时处理器的寄存器中的数据。
- I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
- 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
- 其他信息
描述完之后,操作系统便利用数据结构对其进行组织。比如通过链表,将每个PCB链接起来
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ljOzIJUg-1670237895160)(C:\Users\DongYu\AppData\Roaming\Typora\typora-user-images\image-20221129194417155.png)]](https://img-blog.csdnimg.cn/0294ea8a882b48b3886eaea0da53221e.png)
所以到最后,所谓的进程管理,变成了对进程对应的PCB进行相关的管理,再通过数据结构转化为对链表的增删查改。
综上所述,准确来说
进程 = 内核数据结构(task_struct)+进程对应的磁盘代码
✏️借助管道使用 ps axj 指令配合 grep 指令来查看指定进程
我们可以在Linux中写一段死循环的程序,便于我们查看进程

#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;
}
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vKTzgNHr-1670237895161)(C:\Users\DongYu\AppData\Roaming\Typora\typora-user-images\image-20221201165024214.png)]](https://img-blog.csdnimg.cn/f1ae5e0b50b542e4a92a7c51ce8f3217.png)
❓当我们中止进程再重新加载,id又会是什么呢?
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CZFvy8LH-1670237895161)(C:\Users\DongYu\AppData\Roaming\Typora\typora-user-images\image-20221201165412289.png)]](https://img-blog.csdnimg.cn/3b9f6167c2944f3d9827ca2e00036716.png)
由图我们可以发现,当我们重新运行程序时,此程序进程的id会与之前不同。因为重新运行也即是重新从磁盘中加载到内存,所以进程的id便会改变。但是我们发现它的父进程id是不变的?那到底是谁来产生的子进程呢?
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BOQX4IVn-1670237895161)(C:\Users\DongYu\AppData\Roaming\Typora\typora-user-images\image-20221201165946457.png)]](https://img-blog.csdnimg.cn/8087e605850642b7b43e76e3f3643e1c.png)
通过具体查看进程,我们发现,test程序的父进程是bash,bash也即是shell外壳。这也证明了在执行指令时,shell为了防止程序有误奔溃,导致自身奔溃,所以安全起见,在运行程序时,shell不会自己去执行指令,而是不断地去派生子进程去执行。所以这也是每个程序进程在不断重新运行时,其父进程保持不变的原因。
认识完子进程父进程,我们是否能够自己手动去创建子进程呢?系统调用接口提供了 fork 让我们实现这个目的
fork 在进程管理中能够起到许多作用,而我们目前作为初步认识进程管理,也不对fork进行过多展开,初识fork即可。
在Linux中我们可以通过指令 man 了解fork的用法
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SGazIEQb-1670237895162)(C:\Users\DongYu\AppData\Roaming\Typora\typora-user-images\image-20221201171938625.png)]](https://img-blog.csdnimg.cn/260b536cbef14c52a93d7c8d1008ca5c.png)
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HJoqxuN2-1670237895162)(C:\Users\DongYu\AppData\Roaming\Typora\typora-user-images\image-20221201172055277.png)]](https://img-blog.csdnimg.cn/f0f0d52e384c4908868d3930a3b5150c.png)
简而言之,fork能够创建子进程✏️我们通过代码验证一下
代码的运行结果发现,printf( )函数我们只写了一次,但是运行结果却调用了2次,正是因为fork执行创建了子进程后,会有两个进程去执行fork( )之后的代码
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/41757
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。