zoukankan      html  css  js  c++  java
  • fork函数和vfork函数

    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     /* if((childPid=fork())==-1)
    13     {
    14         printf("Fork error %s
    ",strerror(errno));
    15         exit(1);
    16     }
    17     else
    18         if(childPid==0)
    19         {
    20             printf("I am the child : %d
    ",getpid());
    21             exit(0);
    22         }
    23         else
    24         {
    25             printf("I am the father : %d
    ",getpid());
    26             exit(0);
    27         } */
    28         switch(childPid=fork()){
    29             case -1:
    30                 printf("Fork error %s
    ",strerror(errno));
    31                 exit(1);
    32             case 0:
    33                 printf("I am the child : %d
    ",getpid());
    34                 exit(0);
    35             default:
    36                 printf("I am the father : %d
    ",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之后父进程才可能被调度运行。(如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。)

    注:由于子进程使用父进程的内存,因此子进程对数据段、堆或栈的任何改变将在父进程恢复执行时为其所见。此外,如果子进程在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 %s
    ",strerror(errno));
    15         exit(1);
    16     }
    17     else
    18         if(childPid==0)         //子进程
    19         {
    20             sleep(1);           //子进程睡眠一秒
    21             printf("I am the child : %d
    ",getpid());
    22             exit(0);
    23         }
    24         else                      //父进程
    25         {
    26             printf("I am the father : %d
    ",getpid());
    27             exit(0);
    28         }
    29     /* switch(childPid=vfork()){
    30             case -1:
    31                 printf("Fork error %s
    ",strerror(errno));
    32                 exit(1);
    33             case 0:               //子进程
    34                 sleep(1);        //子进程睡眠一秒
    35                 printf("I am the child : %d
    ",getpid());
    36                 exit(0);
    37             default:            //父进程
    38                 printf("I am the father : %d
    ",getpid());
    39                 exit(0);
    40                 
    41         } */
    42     return 0;
    43 }
    vfork_pid.c

    结果:

     

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

    参考资料

    Linux/Unix系统编程手册

    Unix环境高级编程

    Linux程序设计

  • 相关阅读:
    卷积神经网路计算公式
    Jupyter Notebook
    vim batch copy -- copy between row1 and row2 to row3
    Intellij 快速复制单行快捷键
    Exception in thread "main" java.lang.NoClassDefFoundError: com/mchange/v2/ser/Indirector
    Mac 下查看隐藏文件
    Mac 连接 mysql
    CC++JavaPython 求字符串长度
    LeetCode-1309 Decrypt String from Alphabet to Integer Mapping
    ❀LeetCode❀-1374. Generate a String With Characters That Have Odd Counts
  • 原文地址:https://www.cnblogs.com/mumu597/p/12880710.html
Copyright © 2011-2022 走看看