本文乃fireaxe原创,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,并注明原作者及原链接。内容可任意使用,但对因使用该内容引起的后果不做任何保证。
作者:fireaxe_hq@hotmail.com
博客:fireaxe.blog.chinaunix.net
1) 先说说fork
fork在linux中用于进程的创建。它实际上是复制了一个与父进程(就是调用fork的进程)一模一样的子进程。其主要复制的内容包括: 进程控制块PCD、数据段与堆栈。代码段是共享的。因为代码段是read-only的,不用担心改写的问题,大家共用一块代码也没什么问题。
调用完fork后,两个进程就分道扬镳了,各干各的互不干扰。可问题是他们两个什么都是一样的,那如何区分谁是谁呢?总不能两个进程干一样的活吧。答案是用fork的返回值区分。返回值是0的子进程,非0的就是父进程。
举个形象点的例子: 新人进公司时都会给分配一台新电脑,一般IT部门都会给与装上Windows操作系统和一堆软件。一台电脑就类似于一个进程,所有电脑最开始都是一样的,唯一的区别是使用的人不一样(相当于进程号)。财务科用它算账,咱们程序猿用它coding。
2) exec的作用
exec指的是一组函数,但他们的用法差别不大,这里就用exec代替了。
exec的目的是启动一个新的程序,它会加载一个新的代码段、新的数据段与堆栈。
在借用上面的例子: 研发部门分配的是预装Windows的电脑,可是开发环境是Linux的,所以要重装系统。这个过程就相当于exec。重装系统第一要务是什么呢?就是要先备份数据。exec也是一样的,这一过程不可逆。
(注意: exec一旦调用成功,不会再返回)
3) 为何fork与exec要配合使用
通常来讲只有linux是不够的,日常办公还是用Windows爽,所以当开发人员需要linux环境时,通常的做法是再申请一台电脑,然后在新电脑上安装linux。
一个进程也一样。父进程并不希望调用新程序后自己就消失,所以就需要fork与exec配合起来使用。先用fork启动一个子进程,然后让它去代替自己去死(启动一个新进程)。
这种用法也是进程创建的标准用法,很少有两个函数单独使用情况。
4) 为何需要vfork
上面提到了fork与exec配合使用的情况有一个缺点: 效率有点低。
fork会复制一份独立的数据段与堆栈,而exec的调用会产生新的数据段与堆栈。这种情况下,前面复制数据段与代码段的行为就没什么意义了。而复制又很浪费时间与空间。为了提高效率,产生了vfork。vfork不会复制数据段与堆栈,它产生的子进程会使用父进程的数据段与代码段。因此用vfork代替fork,从效率上看很划算。
5) vfork的缺点
vfork带来效率提升的同时,也引入了一些麻烦。首先是数据段与堆栈的共享。父子进程可能互相影响。为了降低风险,vfork调用后父进程会阻塞到子进程exec被调用。这样能够避免父进程影响子进程。而子进程对父进程的影响则要靠程序员自己控制。
因为共享,子进程对堆栈与数据段的任何改动都会对父进程产生同样影响。所以调用vfork后,要尽快调用exec,以降低风险。vfork与exec之间的操作也要小心的设计。
另外,vfork结束时必须调用exit,否则会导致父进程的异常,原因似乎是堆栈被改写了。
互相影响的风险非常之大,所以能不用vfork,尽量不要用。
6) fork真的比vfork效率低吗
实际上,fork并不会立刻复制数据段与堆栈。而是在它们发生修改时才会复制,而且通过MMU的使用,每次复制只会复制4K。通过写时拷贝的方式,fork极大的提升了效率,而且安全性更高。
7) vfork难道没用了吗
个人觉得vfork还是有用的,但最好能对 vfork+exec 的使用加以限制。
很多操作系统提供了Spawn的操作,这个类似于vfork+exec,但通过吧两个接口封装成一个函数的方式,有效的避免了子进程改写父进程的风险。所以在系统设计时,可以先考虑提供一组vfork加exec的封装。
8) 结束语
linux的系统调用强调的是简单,它们只提供最基本的操作,这样做的好处是灵活。但过灵活度越高,则对程序员的要求越高。
exec系列共有六个函数,所以与fork与vfork配合后会产生12中组合。我的想法是只提供下面三个接口,尽量限制程序员的灵活性:
fork
execlp
spawn (vfork + execlp)
本文乃fireaxe原创,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,并注明原作者及原链接。内容可任意使用,但对因使用该内容引起的后果不做任何保证。
作者:fireaxe_hq@hotmail.com
博客:fireaxe.blog.chinaunix.ne
阅读(3469) | 评论(2) | 转发(1) |