《TCP/IP网络编程》第 10 章 多进程服务器端 笔记( 三 )


#include #include int main(int argc, char *argv[]){pid_t pid = fork();if (pid == 0){puts("Hi, I am a child Process");}else{printf("Child Process ID: %d \n", pid);sleep(30);}if (pid == 0)puts("End child proess");elseputs("End parent process");return 0;}
编译运行:
gcc zombie.c -o zombie./zombie
结果:

《TCP/IP网络编程》第 10 章 多进程服务器端 笔记

文章插图
因为暂停了 30 秒,所以在这个时间内可以验证一下子进程是否为僵尸进程 。
通过 ps au 命令可以看出,子进程仍然存在,并没有被销毁,僵尸进程在这里显示为 Z+.30秒后,红框里面的两个进程会同时被销毁 。
利用 ./ &可以使程序在后台运行,不用打开新的命令行窗口 。
10.2.3 销毁僵尸进程 1:利用 wait 函数
如前所述,为了销毁子进程,父进程应该主动请求获取子进程的返回值 。下面是发起请求的具体方法 。有两种,下面的函数是其中一种 。
#include pid_t wait(int *statloc);/*成功时返回终止的子进程 ID ,失败时返回 -1*/
调用此函数时如果已有子进程终止,那么子进程终止时传递的返回值(exit 函数的参数返回值,main 函数的返回值)将保存到该函数的参数所指的内存空间 。但函数参数指向的单元中还包含其他信息,因此需要用下列宏进行分离:
《TCP/IP网络编程》第 10 章 多进程服务器端 笔记

文章插图
也就是说,向 wait 函数传递变量的地址时,调用 wait 函数后应编写如下代码:
if (WIFEXITED(status)){puts("Normal termination");printf("Child pass num: %d", WEXITSTATUS(status));}
根据以上内容,有如下示例:
#include #include #include #include int main(int argc, char *argv[]){int status;pid_t pid = fork(); //这里的子进程将在第13行通过 return 语句终止if (pid == 0){return 3;}else{printf("Child PID: %d \n", pid);pid = fork(); //这里的子进程将在 21 行通过 exit() 函数终止if (pid == 0){exit(7);}else{printf("Child PID: %d \n", pid);wait(&status);//之间终止的子进程相关信息将被保存到 status 中,同时相关子进程被完全销毁if (WIFEXITED(status)) //通过 WIFEXITED 来验证子进程是否正常终止 。如果正常终止,则调用 WEXITSTATUS 宏输出子进程返回值printf("Child send one: %d \n", WEXITSTATUS(status));wait(&status); //因为之前创建了两个进程,所以再次调用 wait 函数和宏if (WIFEXITED(status))printf("Child send two: %d \n", WEXITSTATUS(status));sleep(30);}}return 0;}
编译运行:
gcc wait.c -o wait./wait
结果:
《TCP/IP网络编程》第 10 章 多进程服务器端 笔记

文章插图
此时,系统中并没有上述 PID 对应的进程,这是因为调用了 wait 函数,完全销毁了该子进程 。另外两个子进程返回时返回的 3 和 7 传递到了父进程 。
这就是通过 wait 函数消灭僵尸进程的方法,调用 wait 函数时,如果没有已经终止的子进程,那么程序将阻塞()直到有子进程终止,因此要谨慎调用该函数 。
10.2.4 销毁僵尸进程 2:使用函数
wait 函数会引起程序阻塞,还可以考虑调用函数 。这是防止僵尸进程的第二种方法,也是防止阻塞的方法 。
#include pid_t waitpid(pid_t pid, int *statloc, int options);/*成功时返回终止的子进程ID 或 0 ,失败时返回 -1pid: 等待终止的目标子进程的ID,若传 -1,则与 wait 函数相同,可以等待任意子进程终止statloc: 与 wait 函数的 statloc 参数具有相同含义options: 传递头文件 sys/wait.h 声明的常量 WNOHANG ,即使没有终止的子进程也不会进入阻塞状态,而是返回 0 退出函数 。*/