自己在刚刚学习Linux进程的时候接触到了一个进程里边的第一个函数fork,最初接触的时候还是感觉比较稀奇的,后来发现也不过如此,之前还写过一个关于fork的博客,fork就是只调用一次,但是却有三个不同返回值的函数,可以通过它的返回值来判断是子进程还是父进程。但是fork和vfrok有什么区别的时候,我只是听说过vfrok并不是很了解两个有什么区别,今天就来总结一下,这两个函数到底有什么区别。
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<error.h>
#include<string.h>
int main()
{
int id=fork();
if(id<0)
{
perror("fork error\n");
return -1;
}
else
{
if(id==0)
{
printf("child pid:%d\n",getpid());
sleep(3);
}
else
{
printf("parent pid:%d\n",getpid());
}
}
return 0;
}
先写一个用fork创建进程的函数
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>
int main()
{
int id=vfork();
if(id<0)
{
perror("vfork error\n");
}
else
{
if(id==0)
{
printf("child pid:%d\n",getpid());
sleep(3);
exit(1);
}
else
{
printf("parent pid:%d\n",getpid());
}
}
return 0;
}
再写一个vfork函数创建进程的程序。
先看一下这两个程序在执行瞬间程序结果的截图。
![](https://i-blog.csdnimg.cn/blog_migrate/afd0eae05836b79d0430ba99d1da9e70.png)
![](https://i-blog.csdnimg.cn/blog_migrate/64253e155823e323ca7dfde427402d12.png)
可以看出来vfork执行的瞬间只有一个子进程输出了信息,父进程没有输出信息,但是fork无论是父进程还是子进程都直接输出了结果。
这里我们的子进程里边都有一个sleep(3)等了3秒之后vfork输出了父进程的语句。
![](https://i-blog.csdnimg.cn/blog_migrate/bcb0691973dbe35d9bf530fda52e1e47.png)
和fork一样了。
所以第一点两个不一样的是1.fork在创建出来父进程和子进程之后会随机选择一个进程来执行,具体执行那个说不准,由调度器来决定,但是我试了几次之后发现都是先执行的父进程,不过定义里边没有确定的结果的。但vfork不一样,vfork是在创建出来子进程之后,必须先执行子进程,等子进程调用结束之后才回去调用父进程,所以在开始的时候没有输出父进程的语句,只有sleep(3)之后,子进程结束之后,才会调用父进程。
第二个特点:vfork里边子进程加了一句话exit(1)这句话在fork里边是没有的,我们去掉这句话再去执行vfrok程序。
![](https://i-blog.csdnimg.cn/blog_migrate/a8e9b4adf754fc24c034fb4a5ec0a0e9.png)
会发现程序死不了,父进程没有变化但是子进程的id在不断的变化,说明子进程在不断的结束不断的创建。这是两个函数第二个区别vfork的子进程是不能使用return来退出的他必须使用exit如果使用return会回到调用vfork函数之前。
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<error.h>
#include<string.h>
int val=100;
int main()
{
int id=fork();
if(id<0)
{
perror("fork error\n");
return -1;
}
else
{
if(id==0)
{
val=200;
printf("child pid:%d val:%d ad:%p\n",getpid(),val,&val);
sleep(3);
}
else
{
printf("parent pid:%d val:%d ad:%p\n",getpid(),val,&val);
}
}
return 0;
}
这里我们创建一个变量,val然后在子进程里边对它进行修改,然后在子进程和父进程里边分别打印出它的值和地址
![](https://i-blog.csdnimg.cn/blog_migrate/1464a73fc4e4cd0bc91fdbc4665c0b86.png)
fork里边父进程和子进程虽然地址是一样的,但是子进程里边的值修改不会改变父进程里边的值。这里的地址是我们所说的虚拟地址,并不是变量实际的地址。所以打印出来了地址一样,但是内容不一样的情况。
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>
int val=100;
int main()
{
int id=vfork();
if(id<0)
{
perror("vfork error\n");
}
else
{
if(id==0)
{
val=200;
printf("child pid:%d val:%d ad:%p\n",getpid(),val,&val);
sleep(3);
exit(1);
}
else
{
printf("parent pid:%d val:%d ad:%p\n",getpid(),val,&val);
}
}
return 0;
}
我们再看vfork
![](https://i-blog.csdnimg.cn/blog_migrate/b520c0d58b550bee288ad88560fddd78.png)
这里子进程里边的修改影响到了父进程,自然地址也是一样的。
这就是fork和vfork的第三个不同,fork函数里边,父进程和子进程是不同的地址空间,子进程的操作不会对父进程起到影响,但是vfork则不同,在调用exit函数之前子进程是在父进程的空间里边运行的,他是可以修改父进程的数据段,堆和栈的。
在最初的时候设计了fork函数,他在创建子进程的时候会创建一个新的地址空间,并且把父进程的情况都给拷贝过去,但是往往来说人们都是运用进程替换把子进程替换成了其他程序,所以这个拷贝的过程就完全浪费了,所以fork函数就变成了用来创建新进程的函数,vfork就是在某种程度上代替了最初的fork。