四、基于多任务的并发服务器( 二 )


View Code
在程序运行后未结束时,可以查看创建的子进程是否被销毁
在运行程序后将创建进程ID为11616的子进程,通过查看进程状态可以知道PID为11616的进程状态为僵尸进程(Z+) 。
3、销毁僵尸进程 1:利用wait函数
为了销毁子进程,父进程需要主动请求获取子进程的结束状态值 。共2中,其中之一就是调用如下函数:
#include /* Wait for a child to die.When one does, put its status in *STAT_LOCand return its process ID.For errors, return (pid_t) -1.This function is a cancellation point and therefore not marked with__THROW.*/extern __pid_t wait (int *__stat_loc);
成功时返回终止的子进程ID,失败时返回-1 。调用此函数,然后有子进程终止,返回值将保存在该函数的参数所指向内存空间,但函数参数执行的单元中还包含其他信息
子进程正常终止时返回“真” true
返回子进程的返回值
下面的代码将不会产生僵尸进程
1 #include2 #include3 #include 4 #include56 int main(int argc, char* argv[]) { 7int status; 8pid_t pid = fork(); 9 10if(pid == 0) return 3;11else {12printf("Child PID : %d \n", pid);13pid = fork();14if(pid == 0) exit(7);15else {16printf("Child PID: %d \n", pid);17wait(&status);18if(WIFEXITED(status))19printf("Child send one: %d \n", WEXITSTATUS(status));20 21wait(&status);22if(WIFEXITED(status)) {23printf("Child send two: %d \n", WEXITSTATUS(status));24}25sleep(30);26}27}28return 0;29 }
View Code
通过() 判断是否正常终止,通过()获取子进程的返回值 。
调用wait函数时,如果没有已终止的子进程,那么程序将阻塞直到有子进程终止,因此需谨慎调用该函数 。
4、销毁僵尸进程 2:利用函数
wait函数会引起程序阻塞,还可以考虑调用函数,这是防止僵尸进程的第二种方法,也是防止阻塞的方法 。
#include /* Wait for a child matching PID to die.If PID is greater than 0, match any process whose process ID is PID.If PID is (pid_t) -1, match any process.If PID is (pid_t) 0, match any process with thesame process group as the current process.If PID is less than -1, match any process whoseprocess group is the absolute value of PID.If the WNOHANG bit is set in OPTIONS, and that childis not already dead, return (pid_t) 0.If successful,return PID and store the dead child's status in STAT_LOC.Return (pid_t) -1 for errors.If the WUNTRACED bit isset in OPTIONS, return status for stopped children; otherwise don't.This function is a cancellation point and therefore not marked with__THROW.*/extern __pid_t waitpid (__pid_t __pid, int *__stat_loc, int __options);
成功时返回终止的子进程ID(或0),失败时返回-1.
__pid:等待终止的目标子进程ID,若传递-1,则与wait函数相同,可以等待任意子进程终止 。
:与wait函数的参数具有相同的含义 。
:传递头文件sys/wait.h中声明的常量,即使没有终止的子进程也不会进入阻塞状态,而是返回0并退出函数 。
1 #include2 #include 3 #include45 int main(int argc, char* argv[]) { 6int status; 7pid_t pid = fork(); 8if(pid == 0) { 9sleep(15);10return 24;11} else {12while (!waitpid(-1, &status, WNOHANG)) {13sleep(3);14puts("sleep 3sec.");15}16if(WIFEXITED(status))17printf("Child send %d \n", WEXITSTATUS(status));18}19return 0;20 }
View Code

四、基于多任务的并发服务器

文章插图
可以看到第14行执行了五次,这也证明了函数并未阻塞 。
三、信号处理
知道了进程的创建和销毁,但还有一个问题没解决,子进程何时终止,调用函数后要无休止地等待吗?
子进程终止的识别主体是操作系统,因此,若操作系统能把如下信息告诉正忙与工作的父进程,将有助于构建高效的程序