进程控制开发之:Linux进程控制编程
3.exit()和_exit()
(1)exit()和_exit()函数说明。
exit()和_exit()函数都是用来终止进程的。当程序执行到exit()或_exit()时,进程会无条件地停止剩下的所有操作,清除包括PCB在内的各种数据结构,并终止本进程的运行。但是,这两个函数还是有区别的,这两个函数的调用过程如图7.4所示。
图7.4exit和_exit函数流程图
从图中可以看出,_exit()函数的作用是:直接使进程停止运行,清除其使用的内存空间,并清除其在内核中的各种数据结构;exit()函数则在这些基础上做了一些包装,在执行退出之前加了若干道工序。exit()函数与_exit()函数最大的区别就在于exit()函数在调用exit系统之前要检查文件的打开情况,把文件缓冲区中的内容写回文件,就是图中的“清理I/O缓冲”一项。
由于在Linux的标准函数库中,有一种被称作“缓冲I/O(bufferedI/O)”操作,其特征就是对应每一个打开的文件,在内存中都有一片缓冲区。每次读文件时,会连续读出若干条记录,这样在下次读文件时就可以直接从内存的缓冲区中读取;同样,每次写文件的时候,也仅仅是写入内存中的缓冲区,等满足了一定的条件(如达到一定数量或遇到特定字符等),再将缓冲区中的内容一次性写入文件。
这种技术大大增加了文件读写的速度,但也为编程带来了一些麻烦。比如有些数据,认为已经被写入文件中,实际上因为没有满足特定的条件,它们还只是被保存在缓冲区内,这时用_exit()函数直接将进程关闭,缓冲区中的数据就会丢失。因此,若想保证数据的完整性,就一定要使用exit()函数。
(2)exit()和_exit()函数语法。
表7.5列出了exit()和_exit()函数的语法规范。
表7.5 exit()和_exit()函数族语法
所需头文件 | exit:#includestdlib.h> |
_exit:#includeunistd.h> | |
函数原型 | exit:voidexit(intstatus) |
_exit:void_exit(intstatus) | |
函数传入值 | status是一个整型的参数,可以利用这个参数传递进程结束时的状态。一般来说,0表示正常结束;其他的数值表示出现了错误,进程非正常结束。 |
(3)exit()和_exit()使用实例。
这两个示例比较了exit()和_exit()两个函数的区别。由于printf()函数使用的是缓冲I/O方式,该函数在遇到“n”换行符时自动从缓冲区中将记录读出。示例中就是利用这个性质来进行比较的。以下是示例1的代码:
/*exit.c*/
#includestdio.h>
#includestdlib.h>
intmain()
{
printf(Usingexit...n);
printf(Thisisthecontentinbuffer);
exit(0);
}
$./exit
Usingexit...
Thisisthecontentinbuffer$
读者从输出的结果中可以看到,调用exit()函数时,缓冲区中的记录也能正常输出。
以下是示例2的代码:
/*_exit.c*/
#includestdio.h>
#includeunistd.h>
intmain()
{
printf(Using_exit...n);
printf(Thisisthecontentinbuffer);/*加上回车符之后结果又如何*/
_exit(0);
}
$./_exit
Using_exit...
$
读者从最后的结果中可以看到,调用_exit()函数无法输出缓冲区中的记录。
小知识 | 在一个进程调用了exit()之后,该进程并不会立刻完全消失,而是留下一个称为僵尸进程(Zombie)的数据结构。僵尸进程是一种非常特殊的进程,它已经放弃了几乎所有的内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。 |
4.wait()和waitpid()
(1)wait()和waitpid()函数说明。
wait()函数是用于使父进程(也就是调用wait()的进程)阻塞,直到一个子进程结束或者该进程接到了一个指定的信号为止。如果该父进程没有子进程或者他的子进程已经结束,则wait()就会立即返回。
waitpid()的作用和wait()一样,但它并不一定要等待第一个终止的子进程,它还有若干选项,如可提供一个非阻塞版本的wait()功能,也能支持作业控制。实际上wait()函数只是waitpid()函数的一个特例,在Linux内部实现wait()函数时直接调用的就是waitpid()函数。
(2)wait()和waitpid()函数格式说明。
表7.6列出了wait()函数的语法规范。
表7.6 wait()函数族语法
所需头文件 | #includesys/types.h> |
函数原型 | pid_twait(int*status) |
函数传入值 | 这里的status是一个整型指针,是该子进程退出时的状态 |
函数返回值 | 成功:已结束运行的子进程的进程号 |
表7.7列出了waitpid()函数的语法规范。
表7.7 waitpid()函数语法
所需头文件 | #includesys/types.h> |
函数原型 | pid_twaitpid(pid_tpid,int*status,intoptions) |
续表
函数传入值 | Pid | pid>0:只等待进程ID等于pid的子进程,不管已经有其他子进程运行结束退出了,只要指定的子进程还没有结束,waitpid()就会一直等下去 | ||
pid=-1:等待任何一个子进程退出,此时和wait()作用一样 | ||||
pid=0:等待其组ID等于调用进程的组ID的任一子进程 | ||||
pid-1:等待其组ID等于pid的绝对值的任一子进程 | ||||
status | 同wait() | |||
options | WNOHANG:若由pid指定的子进程不立即可用,则waitpid()不阻塞,此时返回值为0 | |||
WUNTRACED:若实现某支持作业控制,则由pid指定的任一子进程状态已暂停,且其状态自暂停以来还未报告过,则返回其状态 | ||||
0:同wait(),阻塞父进程,等待子进程退出 | ||||
函数返回值 | 正常:已经结束运行的子进程的进程号 | |||
使用选项WNOHANG且没有子进程退出:0 | ||||
调用出错:-1 |
评论