1.僵尸进程、孤儿进程
僵尸进程:当一个子进程结束运行(一般是调用exit、运行时发生致命错误或收到终止信号所导致)时,子进程的退出状态(返回值)会报给操作系统,系统则以SIGCHLD信号告知父进程,此时子进程的进程控制块(PCB)仍驻留在内存中。父进程收到SIGCHLD后,会调用wait()函数获取子进程的退出状态,然后内核就可以从内存中释放已结束的子进程的PCB;而如若父进程没有这么做的话,子进程的PCB就会一直驻留在内存中,即成为僵尸进程。
孤儿进程:当父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作,因此孤儿进程并没有什么危害,系统中会经常有这种情况。
2.wait、waitpid函数的使用方法
wait、waitpid函数由父进程调用来读取子进程的返回信息,使子进程完全终止。
【1】pid_t wait(int *status);
wait函数会在父进程中阻塞,等待子进程结束,如果子进程结束,则返回子进程的PID。如果没有子进程则立刻返回-1。
【2】pid_t waitpid(pid_t pid, int *status, int options);
waitpid函数等待子进程结束(options设置为WNOHANG时为非阻塞),如果子进程结束,则返回子进程的PID。如果没有子进程则立刻返回-1,如果是非阻塞的并且子进程还没有结束,则返回0。
由于这两个函数会阻塞等待(非阻塞时也需要轮询执行),所以常规使用方式为:当子进程退出时会给父进程发送SIGCHID信号,因此父进程捕获SIGCHID信号,并在信号处理函数中调用waitpid函数来结束一个子进程。如下:
void sig_chld(int signo) { pid_t pid; int stat; while((pid = waitpid(-1, &stat, WNOHANG)) > 0){ printf("child %d terminated\n", pid); } return; } signal(SIGCHLD, sig_chld);
3.问题
问题1:如果有多个子进程,则任意一个子进程结束时,wait函数就会返回,所以此时可以循环判断wait返回-1时(另外返回-1时,errno 等于EINTR时表示中断,所以此时需要继续循环等待),才表示所有子进程都退出了。