进程的退出分为了两大类,一类是正常的退出,另一类是非正常的退出。
正常退出时有五种情况,分别是
①main函数调用return
②进程调用exit(),标准c库
③进程调用_exit()或者_Exit(),属于系统调用
④进程最后一个线程返回
⑤最后一个线程调用pthread_exit
非正常退出时有3种情况,分别是
①使用abort终止
②进程收到某些信号的时候,如使用ctrl+c终止
③最后一个线程对取消(cancellation)请求做出响应
这里我们主要来用exit函数来讲解子进程正常退出
一、验证子进程正常退出,父进程有无调用wait函数的区别
1.父进程无调用wait函数,程序如下
运行结果如下,我们可以看到子进程的ID号是2298,父进程的ID是2297。我们使用
ps -aux|grep a.out命令后可以发现父进程正在运行,状态是S+;子进程的状态是S+,代表僵尸进程。所谓僵尸进程就是说“死而不僵”,看似结束了,但是还存在,就是不工作。同时大家应该还可以看到2394的存在,这是因为使用了ps -aux|grep a.out命令产生了新的进程
2. 父进程调用wait函数,程序如下
运行结果如下,可以看到子进程运行结束后已经彻底消失,不存在僵尸进程。
二、验证子进程正常退出,wait函数功能的验证
wait函数具有阻塞功能,可以然子进程先运行完,父进程才可以运行。wait函数还可以存放子进程退出状态(就是子进程在调用exit函数时,exit的参数)。我们知道,fork函数创建的进程子进程和父进程的运行时没有规律的,两个进程是“抢着”运行,父进程是不会等待子进程的。下面我们就利用fork函数验证的wait函数的阻塞功能。代码如下
运行结果如下,我们可以看到父进程是等到子进程结束之后才开始运行的。子进程在结束的时候exit函数的参数是3,wait函数的参数status原来是10,现在变成了3。说明wait函数具有阻塞功能,还可以存放子进程退出状态。
这里有一个小细节,打印ststus的值的时候,你不能直接写ststus=%d\n"status,而是写成
ststus=%d\n",WEXITSTATUS(status)的样子,没办法,书本规定的。
三、子进程变成孤儿进程
如果创建了子进程,并且父进程运行完了之后,就直接结束了,这时候子进程就会变成了孤儿进程。就好比一个孩子刚出世,父亲没了一个道理。但是linux中为了防止孤儿进程较多,init进程会收留孤儿进程,变成这些孤儿进程的父进程。这就好比刚出生的孩子没了亲生父亲,但是却有个后爹。
下面我们用代码验证一下
运行结果如下,这里还有个小问题,就是有可能你运行出来的“养父”pid的结果不是1。这是因为我们目前使用的是在图形界面打开的terminal是伪终端,需要切换界面,切换到字符型界面,命令如下:
图形界面切换到字符型界面:
Crtl+Alt+F3/Ctrl+Fn+Alt+F3
字符型界面切换到图形界面:
Ctrl+Alt+F2/Ctrl+Fn+Alt+F2
再运行程序,父进程pid变为1.成功。(细节可参考这位大佬的博客,http://t.csdnimg.cn/KsvG7)
下图就是切换到字符型界面的结果