首页 > 代码库 > fork小续
fork小续
pid_t pid = fork();
1.根据fork的返回值区分父子进程:
fork 函数返回两次, >0 表示父进程,返回值为子进程ID; =0 表示子进程; <0 出错。
可用代码表示为:
1 if( ( pid = fork() ) < 0 ){ 2 //error 3 } 4 else if( pid == 0 ){ 5 //child 6 } 7 else{ 8 //parent 9 }
2.进程调用wait等待子进程的退出:
系统调用wait做两件事:a.wait暂停调用它的进程直到子进程结束;b.wait取得子进程结束时传给exit的值。
系统调用wait的两个特征:a.wait阻塞调用它的进程直到子进程结束;b.wait返回结束进程的PID。
父进程必须要回收子进程,这时必须用wait/waitpid。不然当子进程结束后,它会变成僵死进程。用"ps -ef"命令查看,可看到其状态为<defunct>。所以,在fork()之后,我们一般执行:waitpid(pid,NUL,0);
参数1: pid表示到等待的子进程ID
参数2: NULL表示对子进程的结束状态不在意。
参数3: 控制选项
1 if( ( pid = fork() ) < 0 ){ 2 //error 3 } 4 else if( pid == 0 ){ 5 //child 6 ... 7 } 8 else{ 9 waitpid( pid, NULL, 0 ); //用于等待子进程结束. 10 }
3. 问题提出——父进程被阻塞:
在调用waitpid后,父进程被阻塞,将不能执行其他的任务,这在监听程序中是不允许的。所以,必须要回收掉子进程,并且父进程不能被阻塞,要解决这个问题,我们可以fork两次,让子进程被init进程托管。
1 if( ( pid = fork() ) < 0 ){ 2 //error 3 } 4 else if( pid == 0 ){ 5 //first child exit ! 6 if( fork() > 0 ){ 7 exit(0); 8 } 9 else{ 10 //second child... 11 } 12 } 13 else{ 14 waitpid( pid, NULL, 0 ); 15 //因为第一个子进程马上退出,所以waitpid在等到其结束时马上返回,第二 16 //个子进程将被init进程托管! 17 }
4.问题提升——子进程结束标志:
我们让子进程被init进程托管,也就等于对它放弃了控制权,没办法知道它什么时候结束的,以及结束的状态是什么。所以,为了父进程不被阻塞,并且能够及时的回收掉子进程。这时,用信号是个不错的选择。
1 int chld_count = 0; 2 3 void sigchd_exit(int signo) 4 { 5 if( waitpid(-1, NULL, WNOHANG) > 0 ) chld_count--; 6 7 printf( "child count: %d\n", chld_count ); 8 } 9 10 void set_sigchd() 11 { 12 signal(SIGCHLD, sigchd_exit); //子程序退出的信号 13 signal(SIGINT, sigchd_exit); //Ctrl+C 14 signal(SIGTERM, sigchd_exit); 15 } 16 17 //..... 18 set_sigchd() 19 if( ( pid = fork() ) < 0 ){ 20 //error 21 } 22 else if( pid == 0 ){ 23 //child 24 ... 25 } 26 else{ 27 chld_count++; 28 }
这时,在程序开始时设置信号处理函数,当子进程结束时,信号处理函数回收子进程,减少子进程计数。fork之后,父进程增加子进程计数。这样子,程序就实时的知道了子进程的个数。也就可以对止之后的fork做出一定的限制。