当前位置: 技术问答>linux和unix
vfork深度解析!!!
来源: 互联网 发布时间:2016-05-12
本文导语: 我们已经知道,fork会将调用进程的所有内容原封不动的拷贝到新产生的子进程中去,这些拷贝的动作很消耗时间,而如果fork完之后我们马上就调用exec,这些辛辛苦苦拷贝来的东西又会被立刻抹掉,这看起来非常不划...
我们已经知道,fork会将调用进程的所有内容原封不动的拷贝到新产生的子进程中去,这些拷贝的动作很消耗时间,而如果fork完之后我们马上就调用exec,这些辛辛苦苦拷贝来的东西又会被立刻抹掉,这看起来非常不划算,于是人们设计了一种"写时拷贝(copy-on-write)"技术,使得fork结束后并不立刻复制父进程的内容,而是到了真正实用的时候才复制,这样如果下一条语句是exec,它就不会白白作无用功了,也就提高了效率
上面这段话高手能不能解释一下,特别是“这些辛辛苦苦拷贝来的东西又会被立刻抹掉”为什么会这样,原因是什么?
“进程的所有内容”是PCB里的内容吗?
我们平时在linux下开发用fork还是vfork?
上面这段话高手能不能解释一下,特别是“这些辛辛苦苦拷贝来的东西又会被立刻抹掉”为什么会这样,原因是什么?
“进程的所有内容”是PCB里的内容吗?
我们平时在linux下开发用fork还是vfork?
|
呵呵
其实上面一段话的意思是LINUX内核用的是一种写时拷贝copy-on-write技术,也就是说fork的时候子进程是完全复制父进程的页面(这里的复制,指子进程未分配独立的页面,共享父进程的页面,只不过复制了父进程的mm_struct页面结构而已,这样好处就是,开销小
但有一个问题?子进程要写的时候怎么办,此时才会真正分配页面,那这个是怎么实现的呢,原来子进程在创建时将父子进程的页面表项改成了写保护,只要父/子进程一方要写此空间时就会触发一次页面异常,由内核来为子进程重新分配页面,修改页面表项目标志
这样的好处是什么呢,让LINUX在创建进程的时候大大降低了开销,能够快速地复制进程就是源于此
vfork一般是系统来调用的,大家都知道LINUX的线程创建就是通过内核调用vfork来实现的.
vfork会复制父进程的copy_files,copy_fs,copy_sighand,而不拷贝mm_struct只是通过指针共享父进程的mm_struct并没有自己的复本,这就是跟fork的区别
其实上面一段话的意思是LINUX内核用的是一种写时拷贝copy-on-write技术,也就是说fork的时候子进程是完全复制父进程的页面(这里的复制,指子进程未分配独立的页面,共享父进程的页面,只不过复制了父进程的mm_struct页面结构而已,这样好处就是,开销小
但有一个问题?子进程要写的时候怎么办,此时才会真正分配页面,那这个是怎么实现的呢,原来子进程在创建时将父子进程的页面表项改成了写保护,只要父/子进程一方要写此空间时就会触发一次页面异常,由内核来为子进程重新分配页面,修改页面表项目标志
这样的好处是什么呢,让LINUX在创建进程的时候大大降低了开销,能够快速地复制进程就是源于此
vfork一般是系统来调用的,大家都知道LINUX的线程创建就是通过内核调用vfork来实现的.
vfork会复制父进程的copy_files,copy_fs,copy_sighand,而不拷贝mm_struct只是通过指针共享父进程的mm_struct并没有自己的复本,这就是跟fork的区别
|
应用编程里的共享内存机制明白吗? 在各自的进程的空存空间里的地址是不一样的,但都是对应同一块物理内存。fork的行为也有点类似,fork后的父子进程的对应的物理内存其实是完全一样的,并没有实际进行任何的物理内存拷贝。只是当你父子任何一个进程要改变内存里的内容是,就会发生6楼所说的写时复制。但6楼说线程的创建是用vfork应该是不对的。
|
父进程中的数据空间和堆、栈可能会产生副本,具体情况要看你使用的是vfork还是fork.fork会产生副本,而vfork则共享这部分内存。
下面是“Unix环境高级编程”里面摘录的一段。更多的内容可能需要你自己去仔细研读了
用f o r k函数创建子进程后,子进程往往要调用一种e x e c函数以执行另一个程序。
当进程调用一种e x e c函数时,该进程完全由新程序代换,而新程序则从其m a i n函数开始执行。
因为调用e x e c并不创建新进程,所以前后的进程I D并未改变。e x e c只是用另一个新程序替换了
当前进程的正文、数据、堆和栈段。
前面曾提及在执行e x e c后,进程I D没有改变。除此之外,执行新程序的进程还保持了原进
程的下列特征:
? 进程I D和父进程I D。
? 实际用户I D和实际组I D。
? 添加组I D。
? 进程组I D。
? 对话期I D。
? 控制终端。
? 闹钟尚余留的时间。
? 当前工作目录。
? 根目录。
? 文件方式创建屏蔽字。
? 文件锁。
? 进程信号屏蔽。
? 未决信号。
? 资源限制。
? tms_utime, tms_stime, tms_cutime以及t m s _ u s t i m e值。
对打开文件的处理与每个描述符的e x e c关闭标志值有关。见图3 - 1以及3 . 1 3 节中对
F D _ C L O E X E C的说明,进程中每个打开描述符都有一个e x e c关闭标志。若此标志设置,则在
执行e x e c时关闭该描述符,否则该描述符仍打开。除非特地用f c n t l设置了该标志,否则系统的
默认操作是在e x e c后仍保持这种描述符打开。
|
用f o r k函数创建子进程后,子进程往往要调用一种e x e c函数以执行另一个程序。
问题是,子进程其实都还没有运行的呀?
而且子进程是
“在什么时候”
“什么地方”
“通过什么方式”
来调用exec中的一个函数的呢?
因为从 exec函数的实现来看,确实是当前进程的可执行文件被我们要执行的那个文件给替换掉了。
以下代码摘至,linux 0.11 内核中exec.c文件中的do_execve()函数:
if (current->executable)
iput (current->executable); // 放回当前进程的原执行文件的inode
current->executable = inode; // 用待执行文件的inode替换原来的执行文件
所以,这么看来,确实是“当前进程(即子进程)”调用exec函数,才能这么做“替换”工作的。
然后就出现了前面的问题了。
现在被这样的东西给搞晕头了。
问题是,子进程其实都还没有运行的呀?
而且子进程是
“在什么时候”
“什么地方”
“通过什么方式”
来调用exec中的一个函数的呢?
因为从 exec函数的实现来看,确实是当前进程的可执行文件被我们要执行的那个文件给替换掉了。
以下代码摘至,linux 0.11 内核中exec.c文件中的do_execve()函数:
if (current->executable)
iput (current->executable); // 放回当前进程的原执行文件的inode
current->executable = inode; // 用待执行文件的inode替换原来的执行文件
所以,这么看来,确实是“当前进程(即子进程)”调用exec函数,才能这么做“替换”工作的。
然后就出现了前面的问题了。
现在被这样的东西给搞晕头了。
|
其实也没什么 啦
关键就是这一句
因为调用exec并不创建新进程,所以前后的进程ID并未改变。exec只是用另一个新程序替换了当前进程的正文、数据、堆和栈段。
你能理解这个 就差不多了
关键就是这一句
因为调用exec并不创建新进程,所以前后的进程ID并未改变。exec只是用另一个新程序替换了当前进程的正文、数据、堆和栈段。
你能理解这个 就差不多了
|
看看exec的作用是什么
|
帮顶
|
呵呵,,,我再来看看,有没进展
|
嗨嗨,那句辛辛苦苦拷贝来的东西太绝了。
为什么要理解它,只要记住就OK了。
为什么要理解它,只要记住就OK了。
|
exec执行后是去执行别的东西了,而不是当前进程,exec会再产生进程的,所以当前进程就没有了
看看exec就知道了
看看exec就知道了
|
fork时拷贝是通过映射的是同一块物理内存实现的,并没有实际进行数据拷贝. exec的时候还会真正替换里面的内容. 这里需要理解虚拟地址空间跟物理地址空间的区别
|
楼主呢?怎么样 了?
|
因為fork很耗費資源,但是exec又是完全替換,所以當然是"浪費辛辛苦苦的工作", 關於vfork,6樓說到關鍵了!
您可能感兴趣的文章:
本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。
本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。