Fork
- Tags
- comp-arch
Is a system-call that clones the current process to create a new-process, duplicating the state of the existing process with a few minor differences. See fork.
Both the child and current process executes the line after the fork, just like the parent. The return value of fork is -1 if it failed, 0 when in the child process and the PID of the child-process when in the parent. The child can later access its parents PID using getppid, however the only way for a parent to know its child's PID is to store the output of fork. Put another way a process can have an arbitrary number of child processes, but only one parent. Therefore there's no method to access a list of all the child processes but there is one to access the parent process PID.
int out = fork();
if (out < 0) {
printf("Failed to fork\n");
} else if (out == 0) {
printf("Hi from the child process. I don't know my parents PID.\n");
} else {
printf("Hi I'm the parent, I made a child process with id: %d.\n", out);
waitpid(out); // Wait for the child to exit before continuing the parent.
}
Note: As a mild, but great, performance improvement the Linux kernel uses copy-on-write behaviour with the address space of forked processes. This means that both processes reference the same address space except when a variable is modified, in which case the data is allocated, copied over, and then modified. As a consequence of this read-only memory is always shared between forked processes.
Fork and FILEs
When a process is forked any open file descriptors are cloned, however the underlying file descriptions are not. This means:
- If a child closes a file-descriptor inherited from its parent, the parents file descriptor remains open.
- A call to read in the child process doesn't move the cursor along in the parent process.
int file = open(...);
if(!fork) {
read(file, ...);
} else {
read(file, ...);
}
if(!fork) {
int file = open(...);
read(file, ...);
} else {
int file = open(...);
read(file, ...);
}
Waiting on Child Processes
The wait and waitpid system-calls block the current thread until a process changes state (from/to one of the child terminated, the child was stopped by a signal or the child was resumed by a signal). Both of these functions take a pointer to an integer that it assigns to the exit-status of a process. The former does so for any child-process of the current process. The latter waits on a specific process instead.
You can use the WIFEXITED
and the WEXITSTATUS
functions to assert whether a process
terminated normally and to parse out the exit code of the process.