指某东西的用途fork
and exec
它体现了 UNIX 的精神,它提供了一种非常简单的方法来启动新进程。
The fork
调用基本上复制了当前进程,在almost任何方式。并非所有内容都会被复制(例如,某些实现中的资源限制),但其想法是创建尽可能接近的副本。
新进程(子进程)获得不同的进程 ID (PID),并将旧进程(父进程)的 PID 作为其父进程 PID (PPID)。因为两个进程现在运行完全相同的代码,所以它们可以通过返回代码来区分哪个是哪个fork
- 子进程获取 0,父进程获取子进程的 PID。当然,这都是假设fork
调用有效 - 如果没有,则不会创建子级,并且父级会收到错误代码。
The exec
call 是一种基本上用新程序替换整个当前进程的方法。它将程序加载到当前进程空间并从入口点运行它。
So, fork
and exec
通常按顺序使用以使新程序作为当前进程的子进程运行。每当您尝试运行类似这样的程序时,Shell 通常都会执行此操作find
- shell 分叉,然后子进程加载find
将程序写入内存,设置所有命令行参数、标准 I/O 等。
但它们不需要一起使用。对于一个程序来说这是完全可以接受的fork
本身没有exec
例如,如果程序包含父代码和子代码(您需要小心所做的事情,每个实现可能都有限制)。这在守护进程中被大量使用(现在仍然如此),这些守护进程只是监听 TCP 端口并fork
自己的副本来处理特定请求,同时父级继续监听。
同样,知道自己已完成并且只想运行另一个程序的程序不需要fork
, exec
进而wait
为了孩子。他们可以直接将子进程加载到他们的进程空间中。
一些 UNIX 实现有一个优化的fork
它使用所谓的“写时复制”。这是一个延迟进程空间复制的技巧fork
直到程序尝试更改该空间中的某些内容。这对于那些仅使用fork
并不是exec
因为他们不必复制整个进程空间。
If the exec
is称为以下fork
(这是最常发生的情况),这会导致写入进程空间,然后将其复制到子进程。
请注意,有一整个家庭exec
calls (execl
, execle
, execve
等等)但是exec
这里的上下文是指其中任何一个。
下图说明了典型的fork/exec
操作其中bash
shell 用于列出目录ls
命令:
+--------+
| pid=7 |
| ppid=4 |
| bash |
+--------+
|
| calls fork
V
+--------+ +--------+
| pid=7 | forks | pid=22 |
| ppid=4 | ----------> | ppid=7 |
| bash | | bash |
+--------+ +--------+
| |
| waits for pid 22 | calls exec to run ls
| V
| +--------+
| | pid=22 |
| | ppid=7 |
| | ls |
V +--------+
+--------+ |
| pid=7 | | exits
| ppid=4 | <---------------+
| bash |
+--------+
|
| continues
V