开发者学堂课程【物联网开发- Linux 高级程序设计全套视频:Vfork】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/660/detail/10995
Vfork
进程的创建 vfork 函数
pid t vfork(void)
这个函数没有参数,有一个 pid t 的返回值,和 fork 函数的形式值是一样的。
(1)功能:
vfork 函数和 fork 函数一样都是在己有的进程中创建一个新的进程,但它们创建的子进程是有区别的。
Fork 是创建一个子进程,子进程是父进程的一个复制品,并且父子进程有独立的进程空间,并且以前说过fork创建一个进程后就是俩个独立的进程。
操作系统调用要看操作系统的算法,谁先输出是不一定的。Fork首先就是可以进行的地址复制,第二就是可以有独立的地址空间,第三是操作系统调用不确定。
(2)返回值:
创建子进程成功,则在子进程中返回0,父进程中返回子进程ID。出错则返回 。
−1。
(3)fork和vfork函数的区别:
①vfork保证子进程先运行,在它调用 exec 或 exit 之后,父进程才可能被调度运行。
为了验证上述内容,可以根据之前 fork.c 文件的观察效果。将 vork.c
改名为 vfork.c 打开浏览。
输入 gcc vfork -o vfork,创建一个进程之后,子进程中挂有的内容,父进程中挂有的内容,此时运行可以看到父子进程是同时进行的,
如下图
再将里面的内容的 fork 改为 vfork。vfork 是保证子进程显示之前,子进程调用exit 或是 exec 函数父进程才会被执行。如果代码这个样写父进程就会一直是 while(1)。
效果如下,可以看到只有子进程在执行,因为使用了vfork。只有调用 exit 或是 exec函数,父进程才会执行。
验证:使用exit函数来查看对父进程的作用
需要加入一个对整型变量的定义,语句为int i;同时修改子进程中的while(1)改为for(i=0;i<5;i++);_exit是不用包含其他头文件的不用书写。
这部分语句为:
Int i;
for(i=0;i<5;i++)
{ printf(“this is son process\n”);
sleep(1);
}
_exit(0);
这个循环结束后会调用exit,之后会调用exit进行执行
输入语句gcc vfork.c -o vfork
./vfork
运行结果如下:
子进程调用的5s后发现父进程也被调用执行了
②vfork和fork一样都创建一个子进程,但它并不将父进程的地址空间完全复制到了进程中,因为调用exec(或exit),于是也就不该访问该地址空间。
vfork的目的一般就是使子进程可以调用exec去启动另外一个新的程序,用新的程序代码替换子进程的代码,所以没有必要复制父进程的代码它会暂时呆在父进程的进程空间,等到exec启动新的进程才回去开辟新的空间。
③相反,在子进程中调用exec或exit之前,它在父进程的地址空间中运行,在exec之后子进程会有自己的进程空间。
这个例子在之前已经验证过了是保证子进程的执行,子进程进行循环之后,再去执行父进程。
验证 vfork 创建子进程与父进程共用一个地址空间
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int var = 10;
int main(int argc ,char *argv[])
{
pid t pid;
int num =9;
pid=vfork();
if(pid<0)
{ perror(“vfork”);
return 0;
}
else if (pid == 0)
{int i;
var++;
num++;
printf(“in son process var -%d\n”,var,num);
_exit(0);
}else
{
printf(“in father process var -%d\n”,var,num);
}
return 0;
}
注意:
在父进程中不用getsleep,因为只有子进程执行了exit()父进程才会被执行。观察var是否发生变化,如果var变为了11,num变为9,则说明这个子进程加的是父进程的变量
运行结果:
var=11,num=10说明子进程是已经加过了的,就验证了用vfork创建的子进程在exit或exec之前用的是父进程的地址空间。
对于调用_exit,也可以直接调用exit,此时要加入头文件include<stdlib.h>,
运行结果如下:没有问题的。
但如果在修改为 return 0
结果如下:
就会出现错误,程序一直运行。Return不能使用的原因是由于,vfork创建的共同子进程,在子进程中它是一个父进程的地址空间,子进程中return的就是main函数值。
一般调用函数的时候都会压到栈里面去,函数调用完后return会发生弹栈。一个进程中就一个main函数,压了一次栈,在进程结束的时候就会增加一次,之后又会return一次,相当于一个main函数弹了两次栈,就会发生栈溢出的现象。
栈溢出就可能导致运行效果不太一样。所以一个main函数弹出两次就不行,这是一个地址空间。但如果是fork的话就没有问题,它是两个地址空间各顾各的。
所以要注意 vfork 的时候不要用 return 进行函数的调用,选择使用_exit或是exit来结束进程。
总之,讲述了两点内容,第一vfork创建子进程的时候保证先运行,当子进程退出了才运行父进程;第二父进程是vfork创建的进程,俩个用的是同一个地址空间,直到exit 之后,才可以有各自的地址空间。