Unix下C语言编程之进程控制

fork与 vfork的区别

调用fork创建的子进程, 将共享父进程的代码空间, 复制父进程数据空间, 如堆栈等,fork之后,子进程和父进程都会继续执行fork调用之后的指令。

子进程对父进程中的同名变量进行修改并不会影响其在父进程中的值。

该函数被调用一次,但返回两次。两次返回是在不同的地址空间返回的,是在各自的进程地址空间返回的,其中子进程的返回值是0,而父进程的返回值则是新子进程的进程ID。
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
int pe_int = 1;
pid_t pid;
if((pid = fork()) == 0){
pe_int++;
fprintf(stderr, "---- begin[child] ----\n");
  // sleep(3);  
fprintf(stderr, "child pid = [%d],parent pid = %d,pe = %d\n", pid,getppid(),pe_int);
execl("/bin/uname", "uname", "-a", 0);
fprintf(stderr, "\n---- end ----\n");
}
else if(pid > 0){
pe_int++;
fprintf(stderr, "---- begin[parent] ----\n");
fprintf(stderr, " pid = [%d],parent pid = %d,pe = %d\n", getpid(),getppid(),pe_int);
}
else
fprintf(stderr, "Fork failed.\n");
//sleep(10);
}
 

vfork比起fork函数更快, vfork创建的子进程并不复制父进程的数据, 在随后的exec调用中系统会复制新程序的数据到内存, 继而避免了一次数据复制过程;父进程以vfork方式创建子进程后将被阻塞, 知道子进程退出或执行exec调用后才能继续运行.当子进程只用来执行新程序时, vfork-exec模型比fork-exec模型具有更高的效率,

另外vfork保证子进程先运行,在它调用exec或exit后父进程才可能调度运行。而fork的父子进程运行顺序是不定的,它取决于内核的调度算法。
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
pid_t pid;
int pe_int=1;
if((pid = vfork()) == 0){
pe_int++;
fprintf(stderr, "---- begin[child] ----\n");
sleep(3);
fprintf(stderr, "child pid = [%d],parent pid =%d,pe = %d\r", pid,getppid(),pe_int);
execl("/bin/uname", "uname", "-a", 0);
fprintf(stderr, "\n---- end ----\n");
}
else if(pid > 0){
pe_int++;
fprintf(stderr, "---- begin[parent] ----\n");
fprintf(stderr, " pid = [%d],parent pid = %d,pe = %d\n", getpid(),getppid(),pe_int);
}
else
fprintf(stderr, "Fork failed.\n");
return 0;

打印变量pe_int 能看出fork会产生副本,而vfork则共享这部分内存;也能看出当父进程以vfork方式创建子进程后将被阻塞


僵死进程
僵死进程是已经终止, 但没有从进程表中清除的进程.
父进程先退出,子进程就成为孤儿进程,父进程变成了1号进程
子进程先退出,父进程尚未查询子进程的状态,成为僵尸进程 

当查看进程(ps)时,可看到defunct字样, 'defunct'代表僵死进程. 对于僵死进程, 不能奢望通过kill命令杀死之, 因为它已经'死'了, 不再接收任何系统信号.
当子进程终止时, 它释放资源, 并且发送SIGCHLD信号通知父进程. 父进程接收SIGCHLD信号,调用wait返回子进程的状态, 并且释放系统进程表资源. 故如果子进程先于父进程终止, 而父进程没有调用wait接收子进程信息,则子进程将转化为僵死进程, 直到其父进程结束.
一般采用如下方法预防僵死进程
(1) wait法
父进程主动调用wait接收子进程的死亡报告, 释放子进程占用的系统进程表资源. 

这里用掉两个方法:
pid_t wait(int *status) :   
      进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程, wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。    
      其中参数status用来保存被收集进程退出时的一些状态,它是一个指向int类型的指针。
pid_t waitpid(pid_t pid,int *status,int options):
      作用与wait相同,但提供两个参数进程ID pid和options

      当pid>0时,只等待进程ID等于pid的子进程,不管其它已经有多少子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。

      当pid=-1时,等待任何一个子进程退出,没有任何限制,pid=0时,等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,
waitpid不会对它做任何理睬。

      当pid<-1时,等待一个
指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值。   
如果使用了WNOHANG参数调用waitpid,即使没有子进程退出,它也会立即返回,不会像wait那样永远等下去。
      而WUNTRACED参数,由于涉及到一些跟踪调试方面的知识,加之极少用到, 

其中waitpid等待特定的子进程, 而wait则返回任一终止状态的子进程; waitpid提供了一个wait的非阻塞版本; 


(2) 托管法
如果父进程先于子进程而死亡, 则它的所有子进程转由进程init领养, 即它所有子进程的父进程ID号变为1. 当子进程结束时init为其释放进程表资源.
(3) 忽略SIGC(H)LD信号
当父进程忽略SIGC(H)LD信号后, 即使不执行wait, 子进程结束时也不会产生僵死进程.
(4) 捕获SIGC(H)LD信号
当父进程捕获SIGC(H)LD信号, 并在捕获函数代码中等待(wait)子进程
(5)两次fork方法
当子进程先退出,孙子进程就被init接管了,于是跟最初的父进程脱离了关系,就不会僵死了


守护进程
所谓守护进程是一个在后台长期运行的进程, 它们独立于控制终端, 周期性地执行某项任务, 或者阻塞直到事件发生, 默默地守护着计算机系统的正常运行. 在UNIX应用中, 大部分socket通信服务程序都是以守护进程方式执行.
完成一个守护进程
#include <assert.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
void ClearChild(int nSignal){
pid_t pid;
int nState;
// WNOHANG非阻塞调用waitpid, 防止子进程成为僵死进程
while((pid = waitpid(-1, &nState, WNOHANG)) > 0);
signal(SIGCLD, ClearChild); // 重新绑定 SIGCLD信号
}
int InitServer(){
pid_t pid;
assert((pid = fork()) >= 0); // 创建子进程
if(pid != 0){ // 父进程退出, 子进程被init托管
sleep(1);
exit(0);
}
assert(setsid() >= 0); // 子进程脱离终端
umask(0); // 清除文件创建掩码
signal(SIGINT, SIG_IGN); // 忽略SIGINT信号
signal(SIGCLD, ClearChild); // 处理SIGCLD信号,预防子进程僵死
return 0;
}
int main()
{
InitServer();
sleep(100);//100后退出 也可以改成while(1) 变成永久
return 0;
}


(2012/10)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值