Linux/Unix进程控制(2)

来源:互联网 发布:淘宝上买的皮肤可信么 编辑:程序博客网 时间:2024/05/16 17:08

vfork函数

vfork函数的调用序列和返回值与fork相同,但两者的语义不同。

vfork用于创建一个新进程,而该新进程的目的是exec一个新程序。vfork与fork都创建一个子进程,但它不将父进程的地址空间复制到子进程中,因为子进程会立即调用exec,于是不会存访问该地址空间。相反,在子进程调用exec或exit之前,它在父进程的空间中运行,也就是说会更改父进程的数据段、栈和堆。vfork和fork另一区别在于:vfork保证子进程先运行,在它调用exec之后父进程才可能被调度运行。

下面是vfork的使用程序:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include"unistd.h"  
  2. #include"stdio.h"  
  3.    
  4. int     glob = 6;       /* external variable in initialized data*/  
  5.    
  6. int  
  7. main(void)  
  8. {  
  9.     int    var;        /* automatic variableon the stack */  
  10.     pid_t  pid;  
  11.    
  12.     var = 88;  
  13.    printf("before vfork\n");  /* we don't flush stdio */  
  14.     if ((pid = vfork()) < 0) {  
  15.         perror("vfork error");  
  16.     } else if (pid == 0) {      /* child */  
  17.         glob++;                 /* modify parent's variables*/  
  18.         var++;  
  19.         _exit(0);               /* child terminates */  
  20.     }  
  21.     /* 
  22.      * Parent continues here. 
  23.      */  
  24.     printf("pid = %d, glob = %d, var =%d\n", getpid(), glob, var);  
  25.     exit(0);  
  26. }  


执行及输出结果如下所示:

chen123@ubuntu:~/user/apue.2e$./a.out

before vfork

pid = 2984, glob= 7, var = 89

可见子进程直接改变了父进程的变量值,因为子进程在父进程的地址空间中运行。

这里子进程调用_exit是因为_exit并不执行标准I/O缓冲的冲洗操作。如果调用exit,该程序结果不确定,依赖于标准I/O库的实现。因为exit有可能关闭标准I/O流,那么会使父进程不产生任何输出。

exit函数

进程有5中正常终止方式,3中异常终止方式。(见上一篇文章)。

对于任意一种终止情形,我们都希望终止进程能够统治父进程它是如何终止的。对于三个终止函数(exit、_exit和_Exit),实现这一点的方法是,将其退出状态作为参数传送给函数。在异常终止情况下,内核产生一个指示其异常终止原因的终止状态。在任意一种情况下,该终止状态的父进程都能使用wait或waitpid函数取得其终止状态。

在调用_exit时,内核将进程的退出状态转换成终止状态。

         对于父进程已经终止的所有进程,他们的父进程都改变为init进程。我们称这些进程有Init领养。一个init的子进程(包括领养进程)终止时,init会调用一个wait函数取得其终止状态。

         对于一个已经终止、但其父进程尚未对其进行善后处理(获取终止子进程的有关信息,释放它仍占有的资源)的进程被称为僵尸进程。子进程终止时,虽然不在运行,但它仍然存在与系统中,进程表中代表子进程的表项不会立刻被释放,因为它的退出码还需要保存在进程表项中以备父进程今后的wait调用使用,也就是说终止子进程与父进程之间的关联还会保持,直到父进程也正常的终止或父进程调用wait才告结束。

0 0
原创粉丝点击