在学习Linux的时候,应该也要思考为什么API是这样的,这样设计的目的/历史原因是什么?要如何设计一个功能强大,容易使用,较高性能的接口?
在重读Operating Systems: Three Easy Pieces的时候看到了这个问题的解答。
在第五章Process API的第5.4中Why?Motivating The API作者做了一些解释。
UNIX通过一对system calls: fork()
和 exec()
(一组函数)来创建新进程。另外可以使用wait()来进行进程等待。
其中fork()
用于创建一个新进程。wait()
用于parent进程等待child结束。exec*用来让子进程执行另一个命令。
回到问题,就是为什么要用两个函数fork()
和exec()
来完成创建新进程这件事?
原因在于这样的设计可以让shell
在fork()
的后面,exec()
的前面调用一些代码,特别对于UNIX中重要的shell
,它可以利用这部分代码可以用来改变子进程的环境(env)等。
基本的流程:
shell
等待用户输入- 用户输入某个
command
+参数 shell
从 filesystem上找到这个command
- 通过调用
fork
创建子进程 - 调用
exec
*去执行命令 - 通过
wait
等待子进程结束(输出结果) - 重复步骤1
通过分离fork()
和exec()
的好处是可以在4)和5)之间允许shell
进行额外的操作,实现诸如pipeline
的功能。 例如下面这个命令:
prompt> wc p3.c > newfile.txt
在fork
之后, 执行wc
这个命令之前,先关闭了stdout
, 然后打开newfile.txt
。在这之后wc
的输出就会到newfile.txt
中了。(在shell
中是应该是用了pipe
)