完整了解UNIX进程控制是十分重要的。
对我们而言,必须熟练掌握的几个函数:fork,exec系列,_exit,wait和waitpid
waitpid可以等待一个特定进程的结束
wait相当于: waitpid( -1, &status, 0 );
关于fork:
如果子进程在父进程之前终止,父进程可以通过wait或者waitpid获得子进程的状态,内核为每个终止子进程保存了一定量的信息
一个已经终止,但是父进程没有做善后处理的进程被称为僵尸进程zombie,ps(1)打印的状态为Z。
如果编写一个长期运行的程序,它fork很多子进程,除非父进程等待取得子进程的终止状态,不然这些子进程终止后就会变成zombie
由init (id为1,在自举过程结束时调用,绝不会终止)收养的进程,它结束时,init一定会调用一个wait函数取得终止状态
所谓“一个init的子进程”,指的可能是init直接产生的进程(比如getty);或者其父进程已经终止,由init收养的进程
子进程正常或者异常终止,内核向它的父进程发送异步SIGCHLD信号
对于SIGCHLD系统默认是忽略
第二个子进程调用sleep(3)保证打印父进程ID的时候第一个子进程已经终止。fork之后父进程和子进程都可以继续执行,并且我们无法预测哪一个先执行。fork之后如果不让第二个子进程休眠,那么它可能比其父进程先执行,于是它打印的父进程ID将是创建它的父进程的ID而不是init进程的1.。
对我们而言,必须熟练掌握的几个函数:fork,exec系列,_exit,wait和waitpid
waitpid可以等待一个特定进程的结束
wait相当于: waitpid( -1, &status, 0 );
关于fork:
如果子进程在父进程之前终止,父进程可以通过wait或者waitpid获得子进程的状态,内核为每个终止子进程保存了一定量的信息
一个已经终止,但是父进程没有做善后处理的进程被称为僵尸进程zombie,ps(1)打印的状态为Z。
如果编写一个长期运行的程序,它fork很多子进程,除非父进程等待取得子进程的终止状态,不然这些子进程终止后就会变成zombie
由init (id为1,在自举过程结束时调用,绝不会终止)收养的进程,它结束时,init一定会调用一个wait函数取得终止状态
所谓“一个init的子进程”,指的可能是init直接产生的进程(比如getty);或者其父进程已经终止,由init收养的进程
子进程正常或者异常终止,内核向它的父进程发送异步SIGCHLD信号
对于SIGCHLD系统默认是忽略
小技巧
如果一个进程fork一个子进程,但不要它等待子进程终止,也不希望子进程处于僵尸状态直到父进程终止,可以fork两次
fork两次避免僵尸进程:
#include <apue.h>
#include <unistd.h>
#include <sys/wait.h>
#define handle_error(msg) \
do { perror(msg); return EXIT_FAILURE; } while(0)
int main(void)
{
pid_t pid;
int status;
if ((pid = fork()) < 0)
handle_error("fork");
else if (pid == 0) { //first child
if ((pid = fork()) < 0)
handle_error("fork");
else if (pid > 0)
exit(0); //parent from the second fork == first child
/* fork twice
* out parent become init soon as real parent call exit()
* */
sleep(2);
printf("second child, parent pid = %ld", (long) getpid());
exit(0);
} else {
/* we are the original process
* not the parent of the second child
* */
if (waitpid(pid, &status, 0) != pid)
handle_error("waitpid");
}
return EXIT_SUCCESS;
}
第二个子进程调用sleep(3)保证打印父进程ID的时候第一个子进程已经终止。fork之后父进程和子进程都可以继续执行,并且我们无法预测哪一个先执行。fork之后如果不让第二个子进程休眠,那么它可能比其父进程先执行,于是它打印的父进程ID将是创建它的父进程的ID而不是init进程的1.。
当原来的进程(exec本程序的进程)终止时,shell打印其提示符,这在第二个子进程打印其父进程ID之前。