当前位置: 首页 > 面试题库 >

请你回答一下fork和vfork的区别

令狐嘉运
2023-03-14
本文向大家介绍请你回答一下fork和vfork的区别相关面试题,主要包含被问及请你回答一下fork和vfork的区别时的应答技巧和注意事项,需要的朋友参考一下

参考回答:

fork的基础知识:

fork:创建一个和当前进程映像一样的进程可以通过fork( )系统调用:

#include <sys/types.h>

#include <unistd.h>

pid_t fork(void);

成功调用fork( )会创建一个新的进程,它几乎与调用fork( )的进程一模一样,这两个进程都会继续运行。在子进程中,成功的fork( )调用会返回0。在父进程中fork( )返回子进程的pid。如果出现错误,fork( )返回一个负值。

最常见的fork( )用法是创建一个新的进程,然后使用exec( )载入二进制映像,替换当前进程的映像。这种情况下,派生(fork)了新的进程,而这个子进程会执行一个新的二进制可执行文件的映像。这种“派生加执行”的方式是很常见的。

在早期的Unix系统中,创建进程比较原始。当调用fork时,内核会把所有的内部数据结构复制一份,复制进程的页表项,然后把父进程的地址空间中的内容逐页的复制到子进程的地址空间中。但从内核角度来说,逐页的复制方式是十分耗时的。现代的Unix系统采取了更多的优化,例如Linux,采用了写时复制的方法,而不是对父进程空间进程整体复制。

 

vfork的基础知识:

在实现写时复制之前,Unix的设计者们就一直很关注在fork后立刻执行exec所造成的地址空间的浪费。BSD的开发者们在3.0的BSD系统中引入了vfork( )系统调用。

#include <sys/types.h>

#include <unistd.h>

pid_t vfork(void);

除了子进程必须要立刻执行一次对exec的系统调用,或者调用_exit( )退出,对vfork( )的成功调用所产生的结果和fork( )是一样的。vfork( )会挂起父进程直到子进程终止或者运行了一个新的可执行文件的映像。通过这样的方式,vfork( )避免了地址空间的按页复制。在这个过程中,父进程和子进程共享相同的地址空间和页表项。实际上vfork( )只完成了一件事:复制内部的内核数据结构。因此,子进程也就不能修改地址空间中的任何内存。

vfork( )是一个历史遗留产物,Linux本不应该实现它。需要注意的是,即使增加了写时复制,vfork( )也要比fork( )快,因为它没有进行页表项的复制。然而,写时复制的出现减少了对于替换fork( )争论。实际上,直到2.2.0内核,vfork( )只是一个封装过的fork( )。因为对vfork( )的需求要小于fork( ),所以vfork( )的这种实现方式是可行的。

 

补充知识点:写时复制

Linux采用了写时复制的方法,以减少fork时对父进程空间进程整体复制带来的开销。

写时复制是一种采取了惰性优化方法来避免复制时的系统开销。它的前提很简单:如果有多个进程要读取它们自己的那部门资源的副本,那么复制是不必要的。每个进程只要保存一个指向这个资源的指针就可以了。只要没有进程要去修改自己的“副本”,就存在着这样的幻觉:每个进程好像独占那个资源。从而就避免了复制带来的负担。如果一个进程要修改自己的那份资源“副本”,那么就会复制那份资源,并把复制的那份提供给进程。不过其中的复制对进程来说是透明的。这个进程就可以修改复制后的资源了,同时其他的进程仍然共享那份没有修改过的资源。所以这就是名称的由来:在写入时进行复制。

写时复制的主要好处在于:如果进程从来就不需要修改资源,则不需要进行复制。惰性算法的好处就在于它们尽量推迟代价高昂的操作,直到必要的时刻才会去执行。

在使用虚拟内存的情况下,写时复制(Copy-On-Write)是以页为基础进行的。所以,只要进程不修改它全部的地址空间,那么就不必复制整个地址空间。在fork( )调用结束后,父进程和子进程都相信它们有一个自己的地址空间,但实际上它们共享父进程的原始页,接下来这些页又可以被其他的父进程或子进程共享。

写时复制在内核中的实现非常简单。与内核页相关的数据结构可以被标记为只读和写时复制。如果有进程试图修改一个页,就会产生一个缺页中断。内核处理缺页中断的方式就是对该页进行一次透明复制。这时会清除页面的COW属性,表示着它不再被共享。

现代的计算机系统结构中都在内存管理单元(MMU)提供了硬件级别的写时复制支持,所以实现是很容易的。

在调用fork( )时,写时复制是有很大优势的。因为大量的fork之后都会跟着执行exec,那么复制整个父进程地址空间中的内容到子进程的地址空间完全是在浪费时间:如果子进程立刻执行一个新的二进制可执行文件的映像,它先前的地址空间就会被交换出去。写时复制可以对这种情况进行优化。

 

fork和vfork的区别:

\1. fork( )的子进程拷贝父进程的数据段和代码段;vfork( )的子进程与父进程共享数据段

\2. fork( )的父子进程的执行次序不确定;vfork( )保证子进程先运行,在调用exec或exit之前与父进程数据是共享的,在它调用exec或exit之后父进程才可能被调度运行。

\3. vfork( )保证子进程先运行,在它调用exec或exit之后父进程才可能被调度运行。如果在调用这两个html" target="_blank">函数之前子进程依赖于父进程的进一步动作,则会导致死锁。

4.当需要改变共享数据段中变量的值,则拷贝父进程。

 类似资料:
  • 本文向大家介绍请你回答一下mongodb和redis的区别相关面试题,主要包含被问及请你回答一下mongodb和redis的区别时的应答技巧和注意事项,需要的朋友参考一下 参考回答: 内存管理机制上:Redis 数据全部存在内存,定期写入磁盘,当内存不够时,可以选择指定的 LRU 算法删除数据。MongoDB 数据存在内存,由 linux系统 mmap 实现,当内存不够时,只将热点数据放入内存,其

  • 本文向大家介绍请你回答一下STL里resize和reserve的区别?相关面试题,主要包含被问及请你回答一下STL里resize和reserve的区别?时的应答技巧和注意事项,需要的朋友参考一下 resize():改变当前容器内含有元素的数量(size()),eg: vector v; v.resize(len);v的size变为len,如果原来v的size小于len,那么容器新增(len-siz

  • 本文向大家介绍请你回答一下git中Merge和rebase区别?相关面试题,主要包含被问及请你回答一下git中Merge和rebase区别?时的应答技巧和注意事项,需要的朋友参考一下 Merge会自动根据两个分支的共同祖先和两个分支的最新提交 进行一个三方合并,然后将合并中修改的内容生成一个新的 commit,即merge合并两个分支并生成一个新的提交,并且仍然后保存原来分支的commit记录 R

  • 本文向大家介绍请你来回答一下C++中 ++i和i++的区别?相关面试题,主要包含被问及请你来回答一下C++中 ++i和i++的区别?时的应答技巧和注意事项,需要的朋友参考一下 ++i先自增1,再返回,i++先返回i,再自增1

  • 本文向大家介绍请你回答一下Array&List, 数组和链表的区别相关面试题,主要包含被问及请你回答一下Array&List, 数组和链表的区别时的应答技巧和注意事项,需要的朋友参考一下 参考回答: 数组的特点: 数组是将元素在内存中连续存放,由于每个元素占用内存相同,可以通过下标迅速访问数组中任何元素。数组的插入数据和删除数据效率低,插入数据时,这个位置后面的数据在内存中都要向后移。删除数据时,

  • 本文向大家介绍请你回答一下软链接和硬链接区别相关面试题,主要包含被问及请你回答一下软链接和硬链接区别时的应答技巧和注意事项,需要的朋友参考一下 参考回答: 为了解决文件共享问题,Linux引入了软链接和硬链接。除了为Linux解决文件共享使用,还带来了隐藏文件路径、增加权限安全及节省存储等好处。若1个inode号对应多个文件名,则为硬链接,即硬链接就是同一个文件使用了不同的别名,使用ln创建。若文