Fundamentals 29 min read

Master Linux Process Management: fork, vfork, exec, wait, and more

This tutorial explains Linux process concepts, how to view and identify processes, the differences between programs and processes, and provides detailed examples of using fork, vfork, wait, exec family functions, system, and popen to create, control, and monitor child processes, including handling zombies and orphans.

Liangxu Linux
Liangxu Linux
Liangxu Linux
Master Linux Process Management: fork, vfork, exec, wait, and more

Process Basics

A program is a static file on disk, while a process is an executing instance of that program. Each process has a unique non‑negative identifier called PID , similar to an ID card.

PID 0 is the swapper (kernel scheduler), PID 1 is the init process that starts user space.

Viewing Processes

Use ps -aux (or ps -ef) combined with grep to filter specific processes, or top for an interactive view.

Parent and Child Processes

When process A creates process B, A becomes the parent and B the child . The child inherits a copy of the parent's memory space.

Fork: Creating a New Process

The fork() system call creates a duplicate of the calling process. It returns 0 in the child and the child's PID in the parent; on error it returns -1.

#include <sys/types.h>
#include <unistd.h>
pid_t pid = fork();
if (pid == 0) {
    // child code
} else if (pid > 0) {
    // parent code
} else {
    // error handling
}

Example printing the PID before and after fork() shows two outputs, confirming two processes.

Using Fork Return Value

Return 0 → child process.

Return >0 → parent process (value is child's PID).

vfork: Faster Child Creation

vfork()

creates a child that shares the parent's address space until the child calls exec or exit. The parent is blocked until the child exits.

#include <sys/types.h>
#include <unistd.h>
pid_t pid = vfork();
if (pid == 0) {
    // child runs first, then calls exit()
    exit(0);
} else {
    // parent resumes after child exits
}

Process Termination

Processes can exit normally via return from main, exit(), _exit(), or _Exit(). Abnormal termination occurs via signals (e.g., SIGINT) or abort(). The kernel always runs cleanup code to close descriptors and free memory.

Waiting for Child Processes

The parent can retrieve a child's termination status using wait(), waitpid(), or waitid(). Macros such as WIFEXITED, WEXITSTATUS, WIFSIGNALED help interpret the status.

#include <sys/wait.h>
int status;
pid_t pid = wait(&status);
if (WIFEXITED(status)) {
    int exit_code = WEXITSTATUS(status);
}
waitpid()

can be non‑blocking with the WNOHANG option.

Zombie and Orphan Processes

If a child exits without the parent calling wait, it becomes a zombie . If the parent terminates before the child, the child becomes an orphan and is adopted by the init process (PID 1), which also reaps zombies.

exec Family Functions

After fork(), a child often replaces its image with a new program using exec functions (e.g., execl, execv, execlp, execvp, execle, execvpe). These calls do not return on success; on failure they return -1 and set errno.

#include <unistd.h>
execl("/bin/ls", "ls", "-l", (char *)NULL);
// or using execvp with argument vector
char *argv[] = {"ps", NULL};
execvp("ps", argv);

The function name hints at its behavior: l for list arguments, v for vector, p to search PATH, e to specify a new environment.

system() Function

system(const char *cmd)

forks a child that runs /bin/sh -c with the given command. It returns the child’s exit status, 127 if the shell cannot be executed, or -1 on error.

#include <stdlib.h>
int ret = system("ls -l");

Note: system() inherits the environment, which can be a security risk for set‑uid programs.

popen() Function

popen()

creates a pipe to a child process running a shell command, returning a FILE* for reading ( "r") or writing ( "w"). Use pclose() to close and obtain the child’s exit status.

#include <stdio.h>
FILE *fp = popen("ps", "r");
char buf[1024];
size_t n = fread(buf, 1, sizeof(buf)-1, fp);
buf[n] = '\0';
printf("%s", buf);
pclose(fp);

Practical Examples

Various code snippets demonstrate:

Creating child processes with fork() and handling return values.

Using vfork() for lightweight child creation.

Collecting exit status with wait() and waitpid().

Replacing a child with another program via exec family.

Running shell commands with system() and capturing output with popen().

Images

Illustrative diagrams (process hierarchy, fork memory layout, zombie/orphan states) are included to visualize concepts.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

System Programmingprocessforkexecwaitzombie
Liangxu Linux
Written by

Liangxu Linux

Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.