Erlo

fork函数和vfork函数

时间:2020-05-13 12:00   阅读:30次   来源:博客园
页面报错
点赞

fork函数

在诸多应用中,创建多个进程是任务分解时行之有效的方法。例如,某一网络服务器进程可在侦听客户端请求的同时,为处理每---请求而创建一新的子进程,与此同时,服务器进程会继续侦听更多的客户端连接请求。以此类手法分解任务,通常会简化应用程序的设计,同时提高了系统的并发性。(即,可同时处理更多的任务或请求。)

1 #include <sys/types.h>     
2 #include <unistd.h>    
3 pid_t fork(void); //返回:子进程中为0,父进程中为子进程I D,出错为-1  

执行调用后将存在两个进程,且每个进程都会从fork()的返回处继续执行。

这两个进程将执行相同的程序文本段,但却各自拥有不同的栈段、数据段以及堆段拷贝。子进程的栈、数据以及栈段开始时是对父进程内存相应各部分的完全复制。执行fork()之后,每个进程均可修改各自的栈数据、以及堆段中的变量,而并不影响另一进程。

注:现在很多的实现并不做一个父进程数据段和堆的完全拷贝,因为在fork之后经常跟随着exec。作为替代,使用了在写时复制( Copy-On-Write, COW)的技术。这些区域由父、子进程共享,而且内核将它们的存取许可权改变为只读的。(详见Linux|Unix系统编程手册)

程序代码则可通过fork()的返回值来区分父、子进程。在父进程中,fork()将 返回新创建子进程的进程ID。

当无法创建子进程时,fork()将返回-1。 失败的原因可能在于,进程数量要么超出了系统针对此真实用户(realuser ID)在进程数量.上所施加的限制(RLIMIT_ NPROC),要么是触及允许该系统创建的最大进程数这一系统级上限。

一般来说,在fork之后是父进程先执行还是子进程先执行是不确定的。这取决于内核所使用的调度算法。如果要求父、子进程之间相互同步,则要求某种形式的进程间通信。

例子:

 1 #include<stdio.h>
 2 #include<sys/types.h>
 3 #include<unistd.h>
 4 #include<sys/wait.h>
 5 #include<stdlib.h>
 6 #include<errno.h>
 7 #include<string.h>
 8 
 9 int main()
10 {
11     pid_t childPid;
12     #zs# if((childPid=fork())==-1)
13     {
14         printf("Fork error %sn",strerror(errno));
15         exit(1);
16     }
17     else
18         if(childPid==0)
19         {
20             printf("I am the child : %dn",getpid());
21             exit(0);
22         }
23         else
24         {
25             printf("I am the father : %dn",getpid());
26             exit(0);
27         } #fzs#
28         switch(childPid=fork()){
29             case -1:
30                 printf("Fork error %sn",strerror(errno));
31                 exit(1);
32             case 0:
33                 printf("I am the child : %dn",getpid());
34                 exit(0);
35             default:
36                 printf("I am the father : %dn",getpid());
37                 exit(0);
38                 
39         }
40     return 0;
41 }

View Code

结果:

 

vfork函数

类似于fork(), vfork()可以为调用进程创建一个新的子进程。然而,vfork()是为子进程立即执行exec()的程序而专门设计的。

#include <sys/types.h>     
#include <unistd.h>    
pid_t vfork(void); //返回:子进程中为0,父进程中为子进程I D,出错为-1  

vfork()与fork()一样都创建一个子进程, 但是它并不将父进程的地址空间完全复制到子进程中,因为子进程会立即调用 exec (或exit),于是也就不会存访该地址空间。不过在子进程调用 exec或exit之前,它在父进程的空间中运行。vfork()和fork()之间的另一个区别是:vfork()保证子进程先运行,在它调用exec或exit之后父进程才可能被调度运行。(如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。)

例子:

 1 #include<stdio.h>
 2 #include<sys/types.h>
 3 #include<unistd.h>
 4 #include<sys/wait.h>
 5 #include<stdlib.h>
 6 #include<errno.h>
 7 #include<string.h>
 8 
 9 int main()
10 {
11     pid_t childPid;
12     if((childPid=vfork())==-1)
13     {
14         printf("Fork error %sn",strerror(errno));
15         exit(1);
16     }
17     else
18         if(childPid==0)         //子进程
19         {
20             sleep(1);           //子进程睡眠一秒
21             printf("I am the child : %dn",getpid());
22             exit(0);
23         }
24         else                      //父进程
25         {
26             printf("I am the father : %dn",getpid());
27             exit(0);
28         }
29     #zs# switch(childPid=vfork()){
30             case -1:
31                 printf("Fork error %sn",strerror(errno));
32                 exit(1);
33             case 0:               //子进程
34                 sleep(1);        //子进程睡眠一秒
35                 printf("I am the child : %dn",getpid());
36                 exit(0);
37             default:            //父进程
38                 printf("I am the father : %dn",getpid());
39                 exit(0);
40                 
41         } #fzs#
42     return 0;
43 }

vfork_pid.c

结果:

 

运行程序时可以看到,程序会停一秒然后分别打印出父子进程的ID.也就是说子进程进来就阻塞一秒,但也没有先去运行父进程,而是让子进程运行完了之后才运行父进程。

 

参考资料

Linux/Unix系统编程手册

Unix环境高级编程

Linux程序设计

评论留言

还没有评论留言,赶紧来抢楼吧~~

吐槽小黑屋()

* 这里是“吐槽小黑屋”,所有人可看,只保留当天信息。

  • Erlo吐槽

    Erlo.vip2020-06-07 10:38:39Hello、欢迎使用吐槽小黑屋,这就是个吐槽的地方。
  • 返回顶部