此文章初步探究一下进程的基本概念,以及僵尸进程与孤儿进程,后续还会对进程有更加深入的学习。
PCB:进程控制块(struct task_struct),初步包含了一下几个模块:
首先写一个非常easy的程序,我们开始gdb,在程序的第4行打下断点,让程序run起来,然后输入disassemble,我们可看到下面这张图:
我们可以看到有一个箭头指向了"0x00000000004004f1 <+4>: movl $0xa,-0x4(%rbp)"这就是程序即将要执行的下一条指令(我们先不关心这个程序到底干了什么,这里面有寄存器和它的偏移量以及汇编指令)。在gdb时候我们一般用n来逐过程,但是要调试汇编指令时候,我们需要用"ni"来调试,如图:
Q:为什么程序计数器里面要保存下一条指令呢?
答:因为当我们只有1核(也就是只有一个CPU时)多个进程时,某些时候,我们的进程可能拿不到CPU资源,当进程再次拿到CPU资源的时候,操作系统必须得知道该从哪继续执行指令,所以程序计数器里必须保存下一条指令。
当程序执行到绿色箭头所指向的那一行时,当此进程被其他进程站区资源而再次获取到CPU资源的时候,我们已经知道即将要执行"=>“命令,但是系统是如何知道”%edx和%eax"这两个寄存器里面的值呢?这就引出了PCB另一个模块,上下文信息。
通过以上例子我们就不难得出,上下文信息里面保存的是寄存器里面的数据。
对于内存指针,学习过c/c++的过程中时常提到"程序地址空间"这个词,和PCB里的内存指针基本相同,只不过命名为进程地址空间。
所谓的进程创建就是让进程再去创建出来一个子进程:
当进程创建失败的时候返回-1
当进程创建成功的时候才有2种返回值:
4. ==0时,返回给子进程
5. >0时,返回给父进程
下面我们来看看基本的例子:
上述程序执行的结果为:
回答2个问题:
2.到底是子进程先运行还是父进程先运行?
答:不确定,因为只有一个CPU多个进程的时候,是抢占式运行的。
所谓的僵尸进程就是让父进程死循环并且子进程退出。在这时候父进程如果不调用wait()或者waitpid()接口的,对子进程的状态不关心,这样导致了子进程的资源没有被释放,形成一种♂️(僵尸进程)。
僵尸进程不工作,但是会浪费掉系统资源(除了1号进程):由于父进程没有尽职尽责,对子进程的状态视而不管,导致子进程没有被及时回收,成为僵死状态,浪费资源。
所谓的孤儿进程就是父进程先于子进程退出,子进程就没了爹,成了孤儿进程,被1号进程所领养了(1号进程会回收子进程的资源)
下面我们测试一下:
Notes:没有孤儿状态这一说法!!