Question
What are the differences between fork
and exec
?
Answer
The use of fork
and exec
exemplifies the spirit of UNIX in that it
provides a very simple way to start new processes.
The fork
call basically makes a duplicate of the current process, identical
in almost every way. Not everything is copied over (for example, resource
limits in some implementations) but the idea is to create as close a copy as
possible.
The new process (child) gets a different process ID (PID) and has the PID of
the old process (parent) as its parent PID (PPID). Because the two processes
are now running exactly the same code, they can tell which is which by the
return code of fork
- the child gets 0, the parent gets the PID of the
child. This is all, of course, assuming the fork
call works - if not, no
child is created and the parent gets an error code.
The exec
call is a way to basically replace the entire current process with
a new program. It loads the program into the current process space and runs it
from the entry point.
So, fork
and exec
are often used in sequence to get a new program running
as a child of a current process. Shells typically do this whenever you try to
run a program like find
- the shell forks, then the child loads the find
program into memory, setting up all command line arguments, standard I/O and
so forth.
But they're not required to be used together. It's perfectly acceptable for a
program to fork
itself without exec
ing if, for example, the program
contains both parent and child code (you need to be careful what you do, each
implementation may have restrictions). This was used quite a lot (and still
is) for daemons which simply listen on a TCP port and fork
a copy of
themselves to process a specific request while the parent goes back to
listening.
Similarly, programs that know they're finished and just want to run another
program don't need to fork
, exec
and then wait
for the child. They can
just load the child directly into their process space.
Some UNIX implementations have an optimized fork
which uses what they call
copy-on-write. This is a trick to delay the copying of the process space in
fork
until the program attempts to change something in that space. This is
useful for those programs using only fork
and not exec
in that they don't
have to copy an entire process space.
If the exec
is called following fork
(and this is what happens mostly),
that causes a write to the process space and it is then copied for the child
process.
Note that there is a whole family of exec
calls (execl
, execle
, execve
and so on) but exec
in context here means any of them.
The following diagram illustrates the typical fork/exec
operation where the
bash
shell is used to list a directory with the ls
command:
+--------+
| 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
As an aside, there's [an interesting
answer](https://retrocomputing.stackexchange.com/questions/8361/process-model-
in-early-unix/24424#24424) over on the Retrocomputing Stack Exchange
site that details some history of
fork
and exec
.