博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux fork() vfork()
阅读量:4167 次
发布时间:2019-05-26

本文共 3190 字,大约阅读时间需要 10 分钟。

对于主进程 fork()返回新建的子进程ID, 子进程fork()返回0

 

进程配置有唯一的进程控制块PCB,由proc结构和usr结构组成。

下面依次介绍进程相关的系统调用:
1:fork()函数          创建一个子进程

#include
/* 提供类型pid_t的定义 */#include
/* 提供函数的定义 */pid_t fork(void);

只看fork的名字,可能难得有几个人可以猜到它是做什么用的。fork系统调用的作用是复制一个进程。当一个进程调用它,完成后就出现两个几乎一模一样的进程,我们也由此得到了一个新进程。据说fork的名字就是来源于这个与叉子的形状颇有几分相似的工作流程。

在Linux 中,创造新进程的方法只有一个,就是我们正在介绍的fork。其他一些库函数,如system(),看起来似乎它们也能创建新的进程,如果能看一下它们的源码就会明白,它们实际上也在内部调用了fork。包括我们在命令行下运行应用程序,新的进程也是由shell调用fork制造出来的。fork有一些很有意思的特征,下面就让我们通过一个小程序来对它有更多的了解。

/* fork_test.c */#include
#inlcude
main(){pid_t pid; /*此时仅有一个进程*/pid=fork();/*此时已经有两个进程在同时运行*/if(pid<0)printf("error in fork!");else if(pid==0)printf("I am the child process, my process ID is %d/n",getpid());elseprintf("I am the parent process, my process ID is %d/n",getpid());}
编译并运行:
$gcc fork_test.c -o fork_test$./fork_testI am the parent process, my process ID is 1991I am the child process, my process ID is 1992
看这个程序的时候,头脑中必须首先了解一个概念:在语句pid=fork()之前,只有一个进程在执行这段代码,但在这条语句之后,就变成两个进程在执行了,这两个进程的代码部分完全相同,将要执行的下一条语句都是if(pid==0)……。

两个进程中,原先就存在的那个被称作“父进程”,新出现的那个被称作“子进程”。父子进程的区别除了进程标志符(process ID)不同外,变量pid的值也不相同,pid存放的是fork的返回值。fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:

  1. 在父进程中,fork返回新创建子进程的进程ID;
  2. 在子进程中,fork返回0;
  3. 如果出现错误,fork返回一个负值;

fork出错可能有两种原因:(1)当前的进程数已经达到了系统规定的上限,这时errno的值被设置为EAGAIN。(2)系统内存不足,这时errno的值被设置为ENOMEM。(关于errno的意义,请参考本系列的第一篇文章。)

所需头文件:

#include <sys/types.h>

#include <unistd.h>

pid_t vfork(void);

功能:

vfork() 函数和 fork() 函数()一样都是在已有的进程中创建一个新的进程,但它们创建的子进程是有区别的。

参数:

返回值:

成功:子进程中返回 0,父进程中返回子进程 ID。pid_t,为无符号整型。

失败:返回 -1。

fork() 与 vfock() 都是创建一个进程,那它们有什么区别呢?

1)fork(): 父子进程的执行次序不确定。

   vfork():保证子进程先运行,在它调用 exec(进程替换) 或 exit(退出进程)之后父进程才可能被调度运行。

2)fork(): 子进程拷贝父进程的地址空间,子进程是父进程的一个复制品。

   vfork():子进程共享父进程的地址空间(准确来说,在调用 exec(进程替换) 或 exit(退出进程) 之前与父进程数据是共享的)

验证:通过 vfork() 创建的子进程会执行完后,才到父进程执行:

[csharp] 
 
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <unistd.h>  
  4.   
  5. int main(int argc, char *argv[])  
  6. {  
  7.     pid_t pid;  
  8.       
  9.     pid = vfork();  // 创建进程  
  10.     if(pid < 0){ // 出错  
  11.         perror("vfork");  
  12.     }  
  13.       
  14.     if(0 == pid){ // 子进程  
  15.         sleep(3); // 延时 3 秒  
  16.         printf("i am son\n");  
  17.           
  18.         _exit(0); // 退出子进程,必须  
  19.     }else if(pid > 0){ // 父进程  
  20.           
  21.         printf("i am father\n");  
  22.     }  
  23.       
  24.     return 0;  
  25. }  

上面的代码,已经让子进程延时 3 s,
结果还是子进程运行结束后,父进程才执行
,运行结果如下:

验证:子进程共享父进程的地址空间

[csharp] 
 
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <unistd.h>  
  4. int a = 10;  
  5. int main(int argc, char *argv[])  
  6. {  
  7.     pid_t pid;  
  8.     int b = 20;  
  9.       
  10.     pid = vfork();  // 创建进程  
  11.     if(pid < 0){ // 出错  
  12.         perror("vfork");  
  13.     }  
  14.       
  15.     if(0 == pid){ // 子进程  
  16.       
  17.         a = 100, b = 200;  
  18.         printf("son: a = %d, b = %d\n", a, b);  
  19.           
  20.         _exit(0); // 退出子进程,必须  
  21.     }else if(pid > 0){ // 父进程  
  22.           
  23.         printf("father: a = %d, b = %d\n", a, b);     
  24.     }  
  25.       
  26.     return 0;  
  27. }  

通常运行结果得知,子进程修改 a, b 的值,会影响到父进程的 a, b, 效果图如下:

vfork() 保证子进程先运行,在它调用 exec(进程替换) 或 exit(退出进程)之后父进程才可能被调度运行。如果子进程没有调用 exec, exit, 程序则会导致死锁,程序是有问题的程序,没有意义,测试代码如下:

[csharp] 
 
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <unistd.h>  
  4.   
  5. int main(int argc, char *argv[])  
  6. {  
  7.     pid_t pid;  
  8.       
  9.     pid = vfork();  // 创建进程  
  10.     if(pid < 0){ // 出错  
  11.         perror("vfork");  
  12.     }  
  13.       
  14.     if(0 == pid){ // 子进程  
  15.       
  16.         printf("i am son\n");  
  17.         sleep(1);  
  18.           
  19.         // 子进程没有调用 exec 或 exit  
  20.     }else if(pid > 0){ // 父进程  
  21.           
  22.         printf("i am father\n");  
  23.         sleep(1);  
  24.     }  
  25.       
  26.     return 0;  
  27. }  

运行结果如下:

所以用 vfork() 创建进程,子进程里一定要调用 exec(进程替换) 或 exit(退出进程),否则,程序会出问题,没有意义

你可能感兴趣的文章
就在昨天,全球 42 亿 IPv4 地址宣告耗尽!
查看>>
Jackson Tree Model Example
查看>>
常用js收集
查看>>
如何防止sql注入
查看>>
springmvc传值
查看>>
在Eclipse中查看Android源码
查看>>
[转]C语言printf
查看>>
对话周鸿袆:从程序员创业谈起
查看>>
Mysql中下划线问题
查看>>
Xcode 11 报错,提示libstdc++.6 缺失,解决方案
查看>>
vue项目打包后无法运行报错空白页面
查看>>
1136 . 欧拉函数
查看>>
面试题:强制类型转换
查看>>
Decorator模式
查看>>
Template模式
查看>>
Observer模式
查看>>
高性能服务器设计
查看>>
图文介绍openLDAP在windows上的安装配置
查看>>
Pentaho BI开源报表系统
查看>>
Pentaho 开发: 在eclipse中构建Pentaho BI Server工程
查看>>