分类: LINUX
2008-10-10 17:14:57
fork()和vfork()的使用
昨天的《操作系统》课上,老师让下次上机做关于进程的实验,因为我这几天正好在看Linux的进程方面的内容,所以就把这几天所学的知识总结一下。
操作系统需要一种机制创建新的进程,fork()和vfork()就是Linux提供给程序开发人员用于创建进程的函数。
Fork()
使用fork()就要包含
在调用fork函数后,fork调用点产生与父进程相同的子进程,也就是说,fork函数后的代码是被父进程和子进程分别执行的。
Vfork()
Vfork系统调用函数与fork()调用比较类似,就不再详细介绍了。
Vfork函数用于创建新的进程,父子进程共享虚拟内存空间。在Linux系统中,vfork()的实现类似于fork(),都是用于创建调用进程的子进程。
两者的区别:
传统的fork()在创建新的子进程的时候会复制所有父进程所拥有的资源。当然,这一特点有它不尽如人意的地方:使用fork()创建新的进程的目的往往不是为了创建一个和父进程完全一样的进程,很多时候是为了调用exec来执行另一个可执行程序。因此,复制所有父进程的资源是多余的操作。
当使用vfork()系统调用来创建子进程的时候,不会复制父进程的相关资源,父子进程将共享地址空间。子进程对虚拟内存空间的任何修改实际上是在修改父进程虚拟内存空间的内容。在使用vfork()创建子进程后,父进程会被阻塞,直到子进程调用了exec或者_exit()退出。子进程不能使用return返回或调用exit(),但是可以调用_exit()。
通过共享父进程的地址空间,vfork()避免了fork()带来的资源复制消耗。
举例说明两者区别:
程序p1.c和p2.c在子进程中修改了全局变量的取值,在父进程中显示同名变量的取值。
//p1.c
#include
#include
#include
int g_var=0;
int main(void)
{
pid_t pid;
int var=1;
//输出fork()调用前的变量取值
printf(“process id:%ld\n”,(long)getpid());
printf(“before execute the fork system call,g_var=%d var=%d\n”,g_var,var);
//在子进程中改变变量取值,并输出
if((pid=fork())<0)
{
perror(“Can’t create a new process”);
return 1;
}
else if(pid==0)
{
g_var++;
var++;
printf(“process id:%ld,g_var=%d var=%d\n”,(long)getpid(),g_var,var);
_exit();
}
//输出父进程中的取值情况
printf(“process id:%ld,g_var=%d var=%d\n”,(long)getpid(),g_var,var);
return 0;
}
用gcc编译并运行,结果
michenggang@michenggang-desktop:~$ gcc –o p1 p1.c
michenggang@michenggang-desktop:~$ ./p1
process id:24537
before execute the fork system call,g_var=0 var=1
process id:24538,g_var=1 var=2
process id:24537,g_var=0 var=1
可以看到在子进程中改变变量不会影响父进程中变量的取值。
修改上边的程序,将其中使用fork()的语句进行替换,使用vfork(),并将代码保存为p2.c。编译并运行,结果
michenggang@michenggang-desktop:~$ gcc –o p2 p2.c
michenggang@michenggang-desktop:~$ ./p2
process id:24574
before execute the fork system call,g_var=0 var=1
process id:24538,g_var=1 var=2
process id:24537,g_var=1 var=2
可以看到子进程修改变量会导致父进程中对应变量值的改变。