Vfork|学习笔记

简介: 快速学习 Vfork

开发者学堂课程【物联网开发- 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,创建一个进程之后,子进程中挂有的内容,父进程中挂有的内容,此时运行可以看到父子进程是同时进行的,

如下图

image.gif再将里面的内容的 fork 改为 vfork。vfork 是保证子进程显示之前,子进程调用exit 或是 exec 函数父进程才会被执行。如果代码这个样写父进程就会一直是 while(1)。

效果如下,可以看到只有子进程在执行,因为使用了vfork。只有调用 exit 或是 exec函数,父进程才会执行。

image.gif验证:使用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后发现父进程也被调用执行了

image.gif②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之前用的是父进程的地址空间。

image.gif

image.gif对于调用_exit,也可以直接调用exit,此时要加入头文件include<stdlib.h>,

运行结果如下:没有问题的。

image.gif但如果在修改为 return 0

结果如下:

就会出现错误,程序一直运行。Return不能使用的原因是由于,vfork创建的共同子进程,在子进程中它是一个父进程的地址空间,子进程中return的就是main函数值。

一般调用函数的时候都会压到栈里面去,函数调用完后return会发生弹栈。一个进程中就一个main函数,压了一次栈,在进程结束的时候就会增加一次,之后又会return一次,相当于一个main函数弹了两次栈,就会发生栈溢出的现象。

栈溢出就可能导致运行效果不太一样。所以一个main函数弹出两次就不行,这是一个地址空间。但如果是fork的话就没有问题,它是两个地址空间各顾各的。

image.gif所以要注意 vfork 的时候不要用 return 进行函数的调用,选择使用_exit或是exit来结束进程。

总之,讲述了两点内容,第一vfork创建子进程的时候保证先运行,当子进程退出了才运行父进程;第二父进程是vfork创建的进程,俩个用的是同一个地址空间,直到exit 之后,才可以有各自的地址空间。

相关文章
|
C语言
C语言 父进程fork()出的多个子进程在结束后,父进程如何回收?
我在网上找了半天都是在说wait()和waitpid()的详解或者是单个子进程的回收。答非所问。 很简单,根据wait()或者waitpid()的函数特性。没有子进程时返回-1。
83 0
|
3月前
|
NoSQL Linux
Linux的fork和vfork
Linux的fork和vfork
|
6月前
|
算法 Unix Linux
Linux系统编程(vfork和fork)
Linux系统编程(vfork和fork)
91 0
|
程序员 Linux Shell
【CSAPP】进程控制 | 系统调用错误处理 | 进程状态 | 终止进程 | 进程创建 | 回收子进程 | 与子进程同步(wait/waitpid) | execve 接口
【CSAPP】进程控制 | 系统调用错误处理 | 进程状态 | 终止进程 | 进程创建 | 回收子进程 | 与子进程同步(wait/waitpid) | execve 接口
201 0
|
物联网 Linux 开发者
Waitpid 函数|学习笔记
快速学习 Waitpid 函数,“Waitpid 函数”,也是“等”。虽然功能和 “Wait” 相同,但是 “Waitpid” 实现的功能比 “Wait” 实现的功能更多。
Waitpid 函数|学习笔记
|
算法 物联网 Linux
创建进程 fork 函数|学习笔记
快速学习创建进程 fork 函数
创建进程 fork 函数|学习笔记
|
物联网 Linux C语言
孤儿进程|学习笔记
快速学习孤儿进程
孤儿进程|学习笔记
|
Linux 调度
vfork() 函数
vfork() 函数
75 0
|
Ubuntu Linux 开发工具
Linux使用fork()方法创建进程
Linux使用fork()方法创建进程
159 0
Linux使用fork()方法创建进程