a. fork: 子进程拷贝父进程的数据段,代码段,代码段和数据段虽然一样,但是独立拥有。
vfork: 子进程与父进程共享数据段
b. fork: 父子进程的执行次序不确定
vfork: 保证子进程先运行,在调用exec或exit 之前与父进程数据是共享的,
在它调用exec或exit之后父进程才可能被调度运行。
c. vfork: 保证子进程先运行,在她调用exec或exit之后父进程才可能被调度运行。
如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
int cnt = 0;
pid_t pid = vfork();
if (0 == pid)
{
++cnt;
printf("the cnt of child process: %d, pid: %d\n", cnt, getpid());
/* exit(0); */
}
else if (pid > 0)
{
++cnt;
printf("the cnt of parent process: %d, pid: %d\n", cnt, getpid());
}
return 0;
}
hostname [4:27] [tmp/demo/vfork] -> gcc -o main process_demo.c
hostname [4:27] [tmp/demo/vfork] -> ./main
the cnt of child process: 1, pid: 15274
the cnt of parent process: 2, pid: 15273
注销exit后
hostname [4:27] [tmp/demo/vfork] -> gcc -o main process_demo.c
hostname [4:27] [tmp/demo/vfork] -> ./main
the cnt of child process: 1, pid: 17024
the cnt of parent process: -145322832, pid: 17023
Segmentation fault
将vfork改为fork
hostname [4:27] [tmp/demo/vfork] -> gcc -o main process_demo.c
hostname [4:40] [tmp/demo/vfork] -> ./main
the cnt of parent process: 1, pid: 26587
the cnt of child process: 1, pid: 26591
在类UNIX系统中,僵尸进程是指完成执行(通过exit系统调用,或运行时发生致命错误或收到终止信号所致),
但并没有释放它的进程控制块PCB(其中存放进程ID、该进程的exit status、以及进程使用的CPU时间总量),
这些资源仍然保存在操作系统的进程表中。
ps aux命令将僵死进程的状态显示为Z
当一个子进程退出时,并不是立即释放其占用的资源(PCB),操作系统会发送SIGCHLD 信号给父进程,父进程对其默认处理是忽略。
如果想响应这个消息,父进程通常在SIGCHLD 信号事件处理程序中,使用wait系统调用来响应子进程的终止。
在这一过程中,操作系统将依次产生如下事件:
(1)向父进程发送SIGCLD信号,子进程进入zombie(僵尸)状态。
(2)父进程接收到SIGCLD信号,进行处理
进程长时间保持僵尸状态一般是错误的并导致资源泄漏。
孤儿进程是父进程已经退出,而它的一个或多个子进程还在运行,那么这些子进程将成为孤儿进程。
孤儿进程将被init进程(PID为1)所收养,并由init进程对它们完成状态回收工作。
僵尸进程测试程序:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
pid_t pid;
printf("before fork\n");
if ((pid = fork()) < 0)
printf("fork error");
else if (0 == pid) // child process
{
exit(0);
}
system("ps -o pid,ppid,state,tty,command");
return 0;
}
output:
./main
before fork
PID PPID S TT COMMAND
17875 20420 S pts/19 ./main
17876 17875 Z pts/19 [main] <defunct>
17877 17875 R pts/19 ps -o pid,ppid,state,tty,command
20420 10909 S pts/19 -csh
如何避免僵尸进程
(1)父进程通过wait和waitpid等函数等待子进程结束,这会导致父进程挂起
(2)如果父进程很忙,那么可以用signal函数为SIGCHLD安装handler。在子进程结束后,父进程会收到该信号,在handler中调用wait回收
(3)如果父进程不关心子进程何时结束,一般在服务器程序中直接忽略SIGCHLD,用signal(SIGCHLD, SIG_IGN),子进程结束后,内核会回收子进程的PCB,不再给父进程发送信号
(4) fork两次,父进程fork一个子进程,然后继续工作,子进程fork一个孙进程后退出,那么孙进程被init接管,孙进程结束后,init会回收。不过子进程的回收要由父进程做
方法(2)程序
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
void handle(int sigid)
{
// wait any process
pid_t pid = waitpid(-1, NULL, 0);
printf("wait %d process to exit\n", pid);
}
int main()
{
pid_t pid;
if (SIG_ERR == signal(SIGCHLD, handle))
{
printf("create signal handler error");
exit(0);
}
if ((pid = fork()) < 0)
printf("fork error");
else if (0 == pid) // child process
{
exit(0);
}
sleep(1);
system("ps -o pid,ppid,state,tty,command");
return 0;
}
output:
./main
wait 30890 process to exit
PID PPID S TT COMMAND
20420 10909 S pts/19 -csh
30889 20420 S pts/19 ./main
30891 30889 R pts/19 ps -o pid,ppid,state,tty,command
wait -1 process to exit
方法(4)程序
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
pid_t pid;
if ((pid = fork()) < 0)
printf("fork son process error");
if (0 == pid) // in son process
{
if ((pid = fork()) < 0)
printf("fork grandson process error");
else if (pid > 0) // exit son process
{
printf("son process, pid = %d, ppid= %d\n", (int)getpid(), (int)getppid());
exit(0);
}
// in the granson process
sleep(2);
system("ps -o pid,ppid,state,tty,command");
exit(0);
}
printf("son process: %d\n", (int)pid);
// wait son process terminate
if (pid != waitpid(pid, NULL, 0))
{
printf("wait son process error");
exit(-1);
}
printf("father process, pid = %d, ppid = %d\n", getpid(), getppid());
printf("exit\n");
exit(0);
}
output:
./main
son process: 19004
son process, pid = 19004, ppid= 19003
father process, pid = 19003, ppid = 20420
exit
$ PID PPID S TT COMMAND
19005 1 S pts/19 ./main
19006 19005 R pts/19 ps -o pid,ppid,state,tty,command
20420 10909 S pts/19 -csh