目录
前言
一、进程
1.1 什么是进程
在上一篇文章中我们讲到了操作系统是如何实现对硬件资源管理的,管理的本质:先描述,再组织!!那么对于进程来说,它是操作系统的动态执行的基本单元,那么操作系统是不是也要对进程进行管理呢?
是的,操作系统也要对进程进行管理,如何管理?先描述,再组织!!
要了解进程,我们必须从程序进行切入,程序是一组指令的有序集合,它本身没有任何运行的含义,它只是一个静态的实体,例如:我们的源文件在进程预处理、编译、汇编、链接之后形成的可执行程序,它是什么?它其实就是一个普通文件被保存在磁盘中!!我们在Linux中通常需要使用./来执行这个程序,这个过程其实是在干什么?执行可执行程序这个过程其实程序就是在向进程转变!!但是我们也知道这个过程是暂时的,执行完这个程序之后就停止了。这也就表名了进程与程序的第二个不同点:进程是暂时的,而程序是永存的!!
下面我对执行程序的过程做一个简单的描述:
我们接下来谈谈操作系统如何对进程进行管理的?先描述,再组织。
进程 = 内核关于进程的相关数据结构 + 当前进程的代码和数据!!
1.2 task_struct的内容
1.3 查看&&杀掉进程
1.3.1 查看进程
既然进程 = 内核关于进程的相关数据结构 + 当前进程的代码和数据,下面我们就来重点讲解PCB描述进程的一些重要属性。
ps ajx | head -1 && ps axj | grep 进程 # 查看指定进程的属性,head -1显示出进程属性的第一行,ajx与axj是一样的。
除了可以通过ps指令来查看进程,我们还可以在/proc目录下查找到该进程以pid为名的目录文件:
当创建一个进程时,/proc目录下会自动创建一个以该进程pid为名的目录文件,里面包含着该进程的各项信息;当终止进程时,此时pcb不再维护该进程的各项属性,进程pid为名的目录文件自然也就不再存在!!
以上仅仅只是展示了两种查看进程属性的方式,那如果我想自己获取进程的属性呢?如何知道当前我已经创建了进程?
我们可以使用系统调用接口函数getpid函数来获取到进程的pid,知道pid了我们也就知道此时已经创建好了一个进程:
接下来我发现一个现象,我重复多次创建myproc这个进程它的pid一直是呈线性递增的,这没有任何问题,因为进程是动态的,但是为什么myproc的父进程的pid一直不变呢??
下面我们就来看看这个ppid为3591的进程它到底是什么:
bash它是命令行解释器,它本质上也是一个进程!因为它有独立的pid;另外这也可以说明一点,在命令行中启动的大部分可执行程序,最终都会变成进程,而该进程对应的父进程都是bash。为什么我们要使用bash去创建子进程替我们执行任务呢?在之前我们讲的shell原理那里我们就已经提到过这一点,这是为了保证bash的安全,当子进程出问题了,父进程bash不会受到任何的影响。
1.3.2 杀掉进程
除了ctrl + c
终止我们的前台程序,我们还能使用特定的指令来杀掉进程:
kill -9 pid # 杀掉某个进程
1.4 创建子进程
在Linux中如何创建子进程?
下面我们来简单使用一下fork函数创建子进程:
从上图中我们确实发现fork创建了一个子进程,它是一个独立的进程,并且它的父进程就是调用fork函数的进程!!这也就说明了父子进程其实是两个独立的执行流,父进程执行一份,子进程执行一份。
但实际上fork函数很少这样用,因为它是有返回值的,下面我们先来看看fork函数的返回值:
如果fork函数调用成功,则将子进程的pid返回给父进程,0返回给子进程;如果调用失败,则返回-1给父进程,子进程创建失败!!
从上图我们确实验证了返回值的正确性,父进程接收的是子进程的pid,子进程接收的是0;但是这里的疑点很多,一个函数有两个返回值?同一个变量的地址相同但是取的内容不一致??这里等到我们讲到进程地址空间再来回答这个问题。
关于fork函数使用最多的场景其实是通常根据返回值分别来执行父子进程相应的任务,下面我们就来简单使用起来吧:
从上图我们可以看到成功调用fork函数之后,父子进程分别执行不同的任务,它们是两个独立的进程,fork成功之后变为2个执行流,所以我们才能看到使用if else if之后还能出现两份不一样的代码!!
Q:fork函数是如何创建子进程的呢?
Q:fork如何看待代码和数据?
Q:如何理解fork出现两个返回值的情况?
关于fork的原理,在后续我们讲到进程地址空间以及进程控制我们就会理解的更加深刻了!!
本篇文章的内容就讲到这里了,如果对于本文有任何问题或者错处欢迎大家评论区相互交流orz~🙈🙈