Linux System Programming · intermediate · ~12 min

fork — duplicating the process

Create a child process and dispatch on the return value.

Overview

fork() creates a copy of the current process. The original is the parent; the copy is the child. After fork, both processes continue from the same line — but fork returns 0 in the child and the child's PID in the parent. This is how Unix creates new processes.

Why it matters

Every command you run in a shell starts with fork. So does every web server that handles requests in subprocesses, every make job running in parallel, every Docker container's first process. Without fork (or its successor clone), Unix would be a single-user operating system.

Core concepts

Copy-on-write. The child inherits an exact copy of the parent's memory, but the kernel doesn't physically copy pages until one side writes — making fork cheap. Return-value branching. pid_t pid = fork(); if (pid == 0) { /* child */ } else { /* parent */ }. Resource inheritance. File descriptors are shared (until one side closes or exec's).

Syntax notes

#include <sys/types.h>
#include <unistd.h>
pid_t pid = fork();
if (pid < 0) { perror("fork"); return 1; }
if (pid == 0) {
    /* child: usually exec or do work, then _exit */
} else {
    /* parent: usually waitpid(pid, ...) */
}

Lesson

pid_t fork(void) duplicates the current process. After it returns:

  • In the child, fork returns 0.
  • In the parent, fork returns the child's PID.
  • On failure, fork returns -1.

Both processes continue from the same point. They have independent memory; modifications in one are not visible to the other.

Code examples

pid_t pid = fork();
if (pid < 0) { perror("fork"); return 1; }
if (pid == 0) {
    /* child */
    printf("child\n"); _exit(0);
}
/* parent */
int st; waitpid(pid, &st, 0);

Common mistakes

  • Using exit (not _exit) in the child runs atexit handlers twice.
  • Forgetting to wait for the child — it becomes a zombie.

Debugging tips

gdb debugging across fork requires set follow-fork-mode child (or 'parent'). pstree -p <pid> shows the process tree. strace -f follows forked children. When a fork test seems to print twice for one parent line — that's correct! Both processes are running the line.

Memory safety

After fork, both processes have valid copies of every pointer — including pointers to in-memory caches that may now be invalid in one side. Be careful with stdio buffers; flush them before fork to avoid duplicated output.

Real-world uses

Every shell, every cron, every webserver's worker pool, the early-90s inetd super-server, Python's multiprocessing module under the hood, Postgres's per-connection backend.

Practice tasks

  1. Write a program that prints 'hello' from both parent and child after fork. 2. Have parent and child print their own PID and getppid(). 3. Combine fork with waitpid so the parent waits for the child.

Summary

fork duplicates the current process. Branch on the return value: 0 means you're the child, non-zero means you're the parent with the child's PID. Combine with exec to run new programs, with wait to clean up — those three syscalls power every Unix.

Practice with these exercises