您的位置:首页 > 其它

fork和vfork的区别

2011-02-17 16:56 141 查看
fork()和vfork()都是创建一个进程,区别在于:

fork():子进程拷贝父进程的数据段和代码段,且父子进程的执行顺序是不确定的

vfork():共享父进程的数据段,确保子进程优先执行,在调用exec或exit之前与父进程共享数据段,在调用exec或exit父进程才可能被调度运行。如果在调用这两个函数之前,子进程依赖于父进程的进一步动作,则会造成死锁。

举例如下:

#include <stdio.h>

#include <unistd.h>

#include <sys/types.h>

void main()

{

pid_t pid;

pid = fork();

if(pid < 0)

{

printf("process create error!/n");

}

else if(pid == 0)

{

printf("i am the child process,ID is %d/n",getpid());

}

else

{

printf("i am the parent process,ID is %d/n",getpid());

}

}

#gcc fork1.c -o fork1

# ./fork1

I am the parent process,ID is 4237

I am the child process,ID is 4238

因为fork()用于从一个已存在的进程中,创建一个新的进程。新的进程为子进程,原来的进程为父进程。fork()的返回值有两个,子进程返回0,父进程返回子进程的进程号,进程号都是非零的整数。在调用pid=fork()之前,只有父进程在运行,而在pid=fork()之后,父子进程都在运行。pid==0则是子进程,pid!=0则是父进程。我们知道fork()在创建进程时,会拷贝父进程的数据段和代码段,所以子进程中也包含了一下代码:

if(pid < 0){

printf("process create error!/n");

}else if(pid == 0){

printf("i am the child process,ID is %d/n",getpid());

}else{

printf("i am the parent process,ID is %d/n",getpid());

}

以上代码在父子进程中个执行一次,所以打印两条语句。

例子:

void main()

{

int count = 0;

pid_t pid;

pid = fork();

count++;

printf("count is %d/n",count);

return 0;

}

# gcc fork2.c -o fork2

# ./fork2

count= 1

count= 1

这里count为什么不是2呢?再强调一次,fork()函数中的子进程拷贝父进程的数据段和代码段。所以

count++;

printf("count is %d/n",count);

在父子进程中各执行一次,但子进程使用的是自己的数据段(这和从父进程中拷贝过来的一模一样)。它们互不影响。

接下来分析vfork()

将上述程序的fork()换成vfork(),结果如下:

count is 1

count is -1210017386

段错误

本来vfock()是共享数据段的,结果应该是 2,为什么不是预想的 2 呢?

知识点:vfrok与fork的一个区别就是vfork保证子进程优先执行,在他调用exec或则exit之后,父进程才可能被调度执行。如果调用者两个函数之前,子进程依赖于父进程的进一步动作则会死锁。将程序做如下修改:
int main()
{
pid_t pid;
int count =0;
pid = vfork();

if(pid == 0){
count ++;
_exit(0);
}else{
count++
printf("the count is %d/n",count);
}

return 0;
}
结果:

count is 2

如果没有_exit(0)的话,子进程没有调用 exec或 exit,所以父进程是不可能执行的,在子进程调用exec或exit 之后父进程才可能被调度运行。 所以我们加上_exit(0);使得子进程退出,父进程执行,这样 else后的语句就会被父进程执行,又因在子进程调用exec或exit之前与父进程数据是共享的,所以子进程退出后把父进程的数据段count改成1了,子进程退出后,父进程又执行,最终就将count 变成了2

为什么会有vfork,因为以前的fork很傻,当它创建一个子进程时,将会创建一个新的地址空间,并且拷贝父进程的资源,而往往在子进程中会执行 exec 调用,这样,前面的拷贝工作就是白费力气了,这种情况下,聪明的人就想出了 vfork,它产生的子进程刚开始暂时与父进程共享地址空间(其实就是线程的概念了),因为这时候子进程在父进程的地址空间中运行,所以子进程不能进行写操作,并且在儿子“ 霸占”着老子的房子时候,要委屈老子一下了,让他在外面歇着(阻塞) ,一旦儿子执行 了 exec或者 exit后,相当于儿子买了自己的房子了,这时候就相当于分家了。

pid: current->pid

cpu: smp_processor_id()

command: current->comm

转自:http://blog.csdn.net/lijierson8/archive/2010/10/11/5932764.aspx
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: