exec 函数可以执行一个进程,是 Run-Time Library 里面的特性,标准上并没有给出什么硬性规定,因此各个操作系统平台上就可以有五花八门的实现了,本文介绍 linux 上的实现鸠占鹊巢和 windows 下的实现功成身退。
在
linux
上,著名的
exec
函数族可谓是无人不晓,它最著名的特性就是可以实现替换当前进程的地址空间,因此你如果在一个进程当中执行了
exec
,那
就不要指望
exec
返回执行
exec
调用点后面的操作了。
exec
并不负责创建进程,他只负责替换地址空间,负责创建进程的是由另一个系统调用来承担,就
是
fork
,所以在
linux
中典型的创建新的执行映像的方式就是
fork+exec
,当然在你不想要当前进程的情况下也可以直接
exec
。而在
windows
下,
exec
却是简单的
CreateProcess+ExitProcess
的封装,在
windows
下一切最终都要落实到
win32API
的,因此
Win32API
相当于多出来的一个层次,而不像
linux
直接进行系统调用完事,从这二者的实现我们可以看出什么端倪吗?
凡是用过
unix
的都知道
unix
的哲学,每次只做并且做好一件事情这个终极哲学,你看
fork
,连参数都没有,就是创建进程,再看
exec
,根本不管进
程的事,就是替换地址空间,只有这样,把如何组合的策略交给用户,用户才可以获得最大的自由,从而开发出丰富的应用程序。
linux
本身是一点策略都不提
供的,它不会帮你做你认为会省力的工作,也就是说,只要是你可以完成的工作它就绝对不插手,比如在不影响当前进程的情况下启动另一个进程,
linux
认为
没有必要直接提供这样一个系统调用,这里的用户指的是所有系统调用层上面的用户,包括库的设计者。库的设计者或者程序员用户可以随意组合这些现有的系统调
用接口,封装成更加方便的接口,只可惜操作系统并不会帮你,举个例子,
fork+exec
就有一个封装函数,叫做
system
。我们反过来看看
windows
的策略,
windows
为了开发者可以最快的进行开发,另外加上它的内核和用户空间是比较同步的进行开发的,联系非常紧密,两个空间非常的
了解对方,因此
windows
往往会直接提供一些策略,这就增加了操作系统和开发者之间的耦合度,不像在
linux
下开发,系统调用接口很稳定,一般不怎
么变化,内核空间和用户空间只需要通过这个稳定的接口层通信就可以了,而且彼此完全可以不了解对方,正如我前一篇文章所说,这种特性带来的就是术业有专攻
的
庞大社区的支持,力量非常强大。既然
windows
提供了一些用户策略,那么它就明显不适合
unix
哲学同样是创建进程
windows
的
CreateProcess
函数几乎为用户做完了全部的事情,包括创建进程,映射程序映像,这就是和
linux
的最大不同了。当然并不能说
windows
不好,它也有自己的哲学,作为一个产品,它的开发者深知自己的产品,另外不管是内核还是用户空间策略都是产品的一部分,因此就没有必要区分那么清了,它的
开发者通过会议的方式进行协作,因此他们之间的通信就不一定要局限在系统调用接口了。
可能有些人会认为
windows
的
exec
的方式更加干净,确实有那么一点意思,
linux
的方式有些罗嗦也有那么一点意思,可是用户真的需要这种所谓的
干净吗?那要看用户是什么样的人了,信奉不同哲学的人往往会因为一点小的分歧大开杀戒。事实上
linux
的
exec
和
windows
的
exec
根本就不是
一个层面上的,在
linux
中,
exec
只是
“
创建进程
”
这件事情的
“
一部分
”
,而在
windows
下,
exec
却包含了
“
创建进程
”
这件事情,但是还不
止这件事情,另外还包括
“
退出当前进程
”
这件事情,用一句俗语区分它们就是,在
linux
中,
exec
的作用是
“
鸠占鹊巢
”
,在
windows
中,
exec
的作用一个是
“
功成
”
另一个是
“
身退
”
。这里就可以看出
linux
和
windows
的设计粒度,显然
linux
更加细化一些,细化的东西组合
起来往往会出现规模效应,功能会很强大,而粗化的东西在扩展的时候功能会受到限制,比如
linux
可以很简单的实现
“
功成
”+“
身退
”
,就是
fork+exec+exit
,其实就是三个只做一件事的系统调用之组合,反过来要在
windows
下实现
“
鸠占鹊巢
”
就不容易了,因此
windows
中
最细的东西都要比这个
“
鸠占鹊巢
”
要粗,于是就受到了限制。这样的话,在
linux
中就可以在保持
pid
不变的情况下重新启动自身,而在
windows
下
这个需求就很难了。
虽然同样都是
exec
函数,在
linux
和
windows
中的地位却大不相同,当然其位置也不同,在
linux
中可以很安心的将之放到系统调用门口,因为
它就做一件事,不会有任何副作用,但是在
windows
下,它的存在纯粹是为了兼容标准
C
,于是就要用
Win32API
来封装
exec
函数,而
Win32API
中却没有替换地址空间这么细粒度的操作,于是乎只好仅仅实现语义,于是最终就有了
CreateProcess+ExitProcess
的
组合,有人可能会问这不也是一个组合吗?是的,这是一个组合,但是这是由只做一件事的函数作为元素组合的吗?显然不是。