如果fork后不进行wait
或waitpid
,那么子进程将会成会僵尸进程。double fork后, second child成为孤儿进程,由init负责后续的清理工作。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main(void) {
pid_t pid;
if ( (pid = fork()) < 0) {
printf("fork error\n"); exit(1);
} else if (pid == 0) {
// first child
if ( (pid = fork()) < 0) {
printf("fork error\n"); exit(1);
} else if (pid > 0) {
// exit first child
exit(0);
}
//等待first child exit,使得下面能够正确得到ppid == init
sleep(2);
printf("second child, ppid = %d\n", getppid());
exit(0);
}
// 清理first child,保证first child不会成为僵尸进程
if (waitpid(pid, NULL, 0) != pid) {
printf("waitpid error\n"); exit(1);
}
exit(0);
}
在第一次fork后进行setsid, 让first child成为session leader并与控制终端脱离,这样second child就无法再获得控制终端了(非session leader)。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
void has_tty()
{
int tty = open("/dev/tty", O_RDWR);
if (tty > 0) {
printf("process %d has tty %d\n", getpid(), tty);
} else {
printf("process %d has no tty\n", getpid());
}
}
int main(void) {
pid_t pid;
if ( (pid = fork()) < 0) {
printf("fork error\n"); exit(1);
} else if (pid == 0) {
// first child
has_tty(); //拥有tty
setsid();
has_tty(); //已经断开tty
if ( (pid = fork()) < 0) {
printf("fork error\n"); exit(1);
} else if (pid > 0) {
// exit first child
exit(0);
}
has_tty(); //已经断开tty
sleep(2);
printf("second child, ppid = %d\n", getppid());
exit(0);
}
// 清理first child,保证first child不会成为僵尸进程
if (waitpid(pid, NULL, 0) != pid) {
printf("waitpid error\n"); exit(1);
}
exit(0);
}
参考: