进程控制之vfork函数

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

vfork用于创建一个新进程,而新进程的目的是exec一个新程序。vfork和fork一样都创建一个子进程,但是它并不将父进程的地址空间完全复制到子进程中,因为子进程会立即调用exec(或exit),于是也就不会存访该地址空间。相反,在子进程调用exec或exit之前,它在父进程的空间中运行

vfork和fork之间的另一个区别是:vfork保证子进程先运行,在它调用exec或exit之后父进程才可能被调度运行。(如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。)

程序清单8-2 vfork函数实例

[root@localhost apue]# cat prog8-2.c
#include "apue.h"

int     glob = 6;       /* external variable in initialized data */

int
main(void)
{
        int     var;    /* automatic variable on the stack */
        pid_t   pid;

        var = 88;
        printf("before vfork
");       /* we don't flush stdout */

        if((pid = vfork()) < 0)
        {
                err_sys("vfork error");
        }
        else if(pid == 0)       /* child */
        {
                glob++;         /* modify variables */
                var++;
                _exit(0);       /* child terminates */
        }
        /*
        * Parent continues here.
        */
        printf("pid = %d, glob = %d, var = %d
", getpid(), glob, var);
        exit(0);
}

运行该程序得到:

[root@localhost apue]# ./prog8-2
before vfork
pid = 15792, glob = 7, var = 89

子进程最变量glob和var做增1操作,结果改变了父进程中的变量值。因为子进程在父进程的地址空间中运行。

注意,在程序清单8-2中,调用了_exit而不是exit。_exit并不执行标准I/O缓冲的冲洗操作。如果调用的是exit而不是_exit,则该程序的输出是不确定的。它依赖于标准I/O库的实现,我们可能会见到输出没有发生变化,或者发现没有出现父进程的printf输出。

如果子进程调用exit,而exit的实现只是冲洗所有标准I/O流,那么我们会见到输出与子进程调用_exit所产生的输出完全相同,没有任何区别。如果exit的实现除了冲洗所有标准I/O流之外,还关闭标准I/O流,那么表示标准输出FILE对象的相关存储区将被清0。因为子进程借用了父进程的地址空间,所以当父进程恢复运行并调用printf时,也就不会产生任何输出,printf返回-1。注意,父进程的STDOUT_FILENO仍旧有效,子进程得到的是父进程的文件描述符数组的副本。

本篇博文内容摘自《UNIX环境高级编程》(第二版),仅作个人学习记录所用。关于本书可参考:http://www.apuebook.com/

原文地址:https://www.cnblogs.com/nufangrensheng/p/3509550.html