linux 的fork 和 vfork


fork

   fork 是linux下创建新进程的函数。 函数原型: pid_t fork void ); 
(pid_t 是一个宏定义 ,其实质是int 被定义在# include < sys/types.h >中)
  返回值: 若成功调用一次则返回两个值,子进程返回0,父进程 返回子进程ID;否则,出错返回-1。
  之所以父进程要返回子进程ID, 是因为我们有pid_t getppid(void) 可以获取一个进程的父进程id。   但是却没有相应的函数可以获取子进程的id,通过fork函数在父进程返回子进程ID,以使得父进程可以知道子进程的id。

#include 
#include 
#include 

int main(int argc, char** argv) {
    fprintf(stdout, "fork test curpid is %d,ppid is %d \n", getpid(), getppid());
    pid_t ret = fork();
    if (ret < 0) {
        fprintf(stdout, "failed to fork \n");
        return -1; 
    } else if (0 == ret) {
        fprintf(stdout, "ret is %d, pid is %d, ppid is %d\n", ret, getpid(), getppid());
    } else{
        fprintf(stdout, "ret is %d, pid is %d, ppid is %d\n", ret, getpid(), getppid());
    }   
    return 0;
}

运行结果:
fork test curpid is 7430,ppid is 851 
ret is 7431, pid is 7430, ppid is 851
ret is 0, pid is 7431, ppid is 7430

可以看出 父进程先还行,返回了子进程id。
子进程后执行了,返回为0

vfork

函数原型:pid_t vfork( void );
该函数和fork类似。成功则父进程返回子进程pid,子进程返回0. 失败返回-1,失败原因在errno中。

为什么会有vfork呢?

因为以前的fork当它创建一个子进程时,将会创建一个新的地址空间,并且拷贝父进程的资源,然后将会有两种行为:

1.执行从父进程那里拷贝过来的代码段

2.调用一个exec执行一个新的代码段

 

当进程调用exec函数时,一个新程序替换了当前进程的正文,数据,堆和栈段。这样,前面的拷贝工作就是白费力气了,这种情况下,聪明的人就想出了vfork。vfork并不复制父进程的进程环境,子进程在父进程的地址空间中运行,所以子进程不能进行写操作,并且在儿子“霸占”着老子的房子时候,要委屈老子一下了,让他在外面歇着(阻塞),一旦儿子执行了exec或者exit后,相当于儿子买了自己的房子了,这时候就相当于分家了。


因此,如果创建子进程是为了调用exec执行一个新的程序的时候,就应该使用vfork



另外还有的 区别就是:fork 是父进程和子进程的先后顺序不确定,而vfork则是子进程先运行,子进程完成后,父进程后运行。 切记注意这点,如果子进程再有等待父进程的行为,那么就死锁了。


另外注意的就是vfork时,子进程一定要exit。 不然会出现段错误。可参见:http://blog.chinaunix.net/uid-24261911-id-2620651.html


你可能感兴趣的:(C,linux)