fork和vfork()函数都可以创建一个新的进程。主要的两个区别如下:
1.vfork()函数在创建子进程时,不会复制父进程的所有资源,相反,子进程共享父进程的内存,
直至其成功执行了exec()或者调用_exit()退出;
2.vfork()函数创建的子进程最后必须调用_exit()函数才能正确退出子进程,不能使用exit()函数。
为了更便于理解fork()和vfork()两个函数创建的子进程的区别,可以使用如下两个测试程序,来分别运行看一下:
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int idata = 111;
int main()
{
int istack = 222;
pid_t ChildPid;
switch (ChildPid = fork())<span style="white-space:pre"> </span>//使用fork创建进程
{
case -1:
printf("fork create error!\n");
exit(1);
case 0:
idata *= 3;
istack *= 3;
printf("Child process, PID = %d,idata = %d,istack = %d\n",getpid(),idata,istack);
default:
sleep(3);
printf("Parent process, PID = %d,idata = %d,istack = %d\n",getpid(),idata,istack);
}
return 0;
}
运行结果:
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int idata = 111;
int main()
{
int istack = 222;
pid_t ChildPid;
switch (ChildPid = vfork())<span style="white-space:pre"> </span>//使用vfork创建进程
{
case -1:
printf("fork create error!\n");
exit(1);
case 0:
idata *= 3;
istack *= 3;
printf("Child process, PID = %d,idata = %d,istack = %d\n",getpid(),idata,istack);
_exit(0);<span style="white-space:pre"> </span>//vfork创建的子进程必须调用_exit()函数才能正确退出
default:
sleep(3);
printf("Parent process, PID = %d,idata = %d,istack = %d\n",getpid(),idata,istack);
}
return 0;
}
运行结果:
如上所示的两组程序逻辑相同,只是分别调用了fork和vfork创建子进程。通过结果,可以看出,在第一个程序(fork)的结果中,在子进程中修改了idata和istack的值,等到再进入父进程时,值没有发生改变;在第二个程序(vfork)的结果中,在子进程中修改了idata和istack的值,等到再进入父进程时,值发生了改变。
通过这个比较,可以总结如下:
1.fork()创建的子进程拥有了自己的栈和数据段拷贝,而且,在子进程中对父进程变量的修改,不会影响父进程;
2.vfork()创建的子进程共享父进程的内存,所以在子进程中对父进程变量的修改,会影响父进程。
另外关于vfork()函数,还想多说几句。不知道大家有没有看过Michael Kerrisk先生编著的《Linux/UNIX系统编程手册(上册)》这本书。在第24章“进程的创建”,第三小节“系统调用vfork()”中,作者特别写了几句:“鉴于vfork()的怪异语义可能会导致一些难以察觉的程序缺陷(bug),除非能给性能带来重大提升(这种情况发生的概率极小),否则应当尽量避免使用这一调用。”对于这几句,目前我还没有什么太深的理解。关于vfork的bug这一点,不知道哪位大神有这方面的经验和教训,可以互相分享讨论一下,大家共同注意。