Process management is a cornerstone of systems programming in C. Understanding how to create, control, and communicate with processes is essential for building robust applications, from simple command-line tools to complex server architectures. This comprehensive guide explores everything from basic process creation to advanced inter-process communication techniques.
What is a Process?
A process is an instance of a running program. It consists of:
- Program code (text segment)
- Data (initialized and uninitialized)
- Stack (function calls, local variables)
- Heap (dynamically allocated memory)
- Process control block (PCB) with metadata
- Open file descriptors
- Environment variables
┌─────────────────────────────────────┐ │ Process │ │ ┌─────────────────────────────┐ │ │ │ Text Segment │ │ │ │ (Program Code) │ │ │ └─────────────────────────────┘ │ │ ┌─────────────────────────────┐ │ │ │ Data Segment │ │ │ │ (Initialized/Uninitialized)│ │ │ └─────────────────────────────┘ │ │ ┌─────────────────────────────┐ │ │ │ Heap │ │ │ │ (Dynamic Memory) │ │ │ └─────────────────────────────┘ │ │ ┌─────────────────────────────┐ │ │ │ Stack │ │ │ │ (Function Calls) │ │ │ └─────────────────────────────┘ │ └─────────────────────────────────────┘
Process IDs and Basic Information
#include <stdio.h> #include <unistd.h> #include <sys/types.h> void print_process_info() { pid_t pid = getpid(); // Current process ID pid_t ppid = getppid(); // Parent process ID uid_t uid = getuid(); // Real user ID uid_t euid = geteuid(); // Effective user ID gid_t gid = getgid(); // Real group ID gid_t egid = getegid(); // Effective group ID printf("Process Information:\n"); printf(" PID: %d\n", pid); printf(" PPID: %d\n", ppid); printf(" UID: %d\n", uid); printf(" EUID: %d\n", euid); printf(" GID: %d\n", gid); printf(" EGID: %d\n", egid); } Process Creation with fork()
1. Basic fork() Usage
#include <stdio.h> #include <unistd.h> #include <sys/wait.h> #include <stdlib.h> void basic_fork() { pid_t pid = fork(); if (pid == -1) { perror("fork failed"); exit(1); } else if (pid == 0) { // Child process printf("Child: PID=%d, PPID=%d\n", getpid(), getppid()); printf("Child: Hello from child process\n"); exit(0); } else { // Parent process printf("Parent: PID=%d, Child PID=%d\n", getpid(), pid); printf("Parent: Waiting for child to complete...\n"); int status; wait(&status); printf("Parent: Child exited with status %d\n", WEXITSTATUS(status)); } } 2. fork() Memory Space Demonstration
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> int global_var = 100; // Data segment void demonstrate_memory_space() { int stack_var = 200; char *heap_var = malloc(100); strcpy(heap_var, "Heap data"); pid_t pid = fork(); if (pid == 0) { // Child process printf("\n--- Child Process ---\n"); printf("Before modification:\n"); printf(" global_var = %d\n", global_var); printf(" stack_var = %d\n", stack_var); printf(" heap_var = %s\n", heap_var); // Modify variables global_var = 999; stack_var = 888; strcpy(heap_var, "Child modified"); printf("\nAfter modification:\n"); printf(" global_var = %d\n", global_var); printf(" stack_var = %d\n", stack_var); printf(" heap_var = %s\n", heap_var); free(heap_var); exit(0); } else { // Parent process wait(NULL); printf("\n--- Parent Process ---\n"); printf("After child modifications:\n"); printf(" global_var = %d (unchanged)\n", global_var); printf(" stack_var = %d (unchanged)\n", stack_var); printf(" heap_var = %s (unchanged)\n", heap_var); free(heap_var); } } 3. fork() with File Descriptors
#include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <sys/wait.h> void demonstrate_fork_file_descriptors() { int fd = open("test.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd == -1) { perror("open"); return; } pid_t pid = fork(); if (pid == 0) { // Child writes to file dprintf(fd, "Child process writing\n"); close(fd); exit(0); } else { // Parent also writes to same file dprintf(fd, "Parent process writing\n"); close(fd); wait(NULL); } } Process Execution with exec() Family
1. exec() Family Overview
#include <unistd.h> #include <stdio.h> #include <stdlib.h> void demonstrate_exec_functions() { // execl: list arguments execl("/bin/ls", "ls", "-l", "-a", NULL); // execlp: uses PATH environment variable execlp("ls", "ls", "-l", NULL); // execv: vector of arguments char *args[] = {"ls", "-l", "-a", NULL}; execv("/bin/ls", args); // execvp: uses PATH with vector execvp("ls", args); // execle: with environment char *env[] = {"PATH=/bin", "USER=test", NULL}; execle("/bin/ls", "ls", "-l", NULL, env); } 2. Complete exec() Example
#include <stdio.h> #include <unistd.h> #include <sys/wait.h> #include <stdlib.h> int execute_command(const char *cmd, char *const argv[]) { pid_t pid = fork(); if (pid == -1) { perror("fork"); return -1; } else if (pid == 0) { // Child process execvp(cmd, argv); // If exec returns, it failed perror("execvp"); exit(1); } else { // Parent process int status; waitpid(pid, &status, 0); if (WIFEXITED(status)) { return WEXITSTATUS(status); } return -1; } } int main() { char *ls_args[] = {"ls", "-l", "-a", NULL}; int result = execute_command("ls", ls_args); printf("Command exited with status: %d\n", result); return 0; } 3. Custom Shell Implementation
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/wait.h> #define MAX_CMD_LEN 1024 #define MAX_ARGS 64 void parse_command(char *cmd, char *args[]) { int i = 0; char *token = strtok(cmd, " \t\n"); while (token != NULL && i < MAX_ARGS - 1) { args[i++] = token; token = strtok(NULL, " \t\n"); } args[i] = NULL; } void execute_pipeline(char *cmds[], int num_cmds) { int pipe_fds[2]; int in_fd = 0; pid_t pid; for (int i = 0; i < num_cmds; i++) { pipe(pipe_fds); pid = fork(); if (pid == 0) { // Child process if (in_fd != 0) { dup2(in_fd, STDIN_FILENO); close(in_fd); } if (i < num_cmds - 1) { dup2(pipe_fds[1], STDOUT_FILENO); } close(pipe_fds[0]); close(pipe_fds[1]); // Parse and execute command char *args[MAX_ARGS]; parse_command(cmds[i], args); execvp(args[0], args); perror("execvp"); exit(1); } close(pipe_fds[1]); if (in_fd != 0) close(in_fd); in_fd = pipe_fds[0]; } // Wait for all children for (int i = 0; i < num_cmds; i++) { wait(NULL); } } int main() { char input[MAX_CMD_LEN]; while (1) { printf("mysh> "); fflush(stdout); if (fgets(input, sizeof(input), stdin) == NULL) { break; } // Remove newline input[strcspn(input, "\n")] = 0; if (strcmp(input, "exit") == 0) { break; } if (strlen(input) == 0) { continue; } // Check for pipe char *commands[MAX_ARGS]; int num_cmds = 0; char *token = strtok(input, "|"); while (token != NULL && num_cmds < MAX_ARGS) { commands[num_cmds++] = token; token = strtok(NULL, "|"); } if (num_cmds == 1) { // Simple command pid_t pid = fork(); if (pid == 0) { char *args[MAX_ARGS]; parse_command(commands[0], args); execvp(args[0], args); perror("execvp"); exit(1); } else { wait(NULL); } } else { // Pipeline execute_pipeline(commands, num_cmds); } } return 0; } Process Termination
1. exit() vs _exit()
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h> void demonstrate_exit_types() { printf("Demonstrating exit() vs _exit()\n"); pid_t pid = fork(); if (pid == 0) { // Child process printf("Child: Using exit()\n"); printf("Child: This buffer will be flushed\n"); exit(0); // Flushes stdio buffers } else { wait(NULL); } pid = fork(); if (pid == 0) { // Child process printf("Child: Using _exit()\n"); printf("Child: This buffer may not be flushed\n"); _exit(0); // No stdio flushing } else { wait(NULL); } } 2. atexit() Registration
#include <stdio.h> #include <stdlib.h> #include <unistd.h> void cleanup_function1(void) { printf("Cleanup 1: Closing resources...\n"); } void cleanup_function2(void) { printf("Cleanup 2: Saving state...\n"); } void cleanup_function3(void) { printf("Cleanup 3: Final message\n"); } void demonstrate_atexit() { // Register cleanup functions (called in reverse order) atexit(cleanup_function3); atexit(cleanup_function2); atexit(cleanup_function1); printf("Program running...\n"); printf("Exit handlers registered\n"); // Normal exit - all handlers called exit(0); // _exit() would NOT call handlers // _exit(0); } Process Waiting and Monitoring
1. wait() and waitpid()
#include <stdio.h> #include <unistd.h> #include <sys/wait.h> #include <stdlib.h> void demonstrate_wait_functions() { pid_t pid; int status; // Create multiple children for (int i = 0; i < 3; i++) { pid = fork(); if (pid == 0) { // Child process printf("Child %d (PID=%d) starting\n", i, getpid()); sleep(i + 1); exit(i * 10); } } // Wait for all children while ((pid = wait(&status)) > 0) { if (WIFEXITED(status)) { printf("Child %d exited with status %d\n", pid, WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { printf("Child %d killed by signal %d\n", pid, WTERMSIG(status)); } } } void demonstrate_waitpid() { pid_t pids[5]; // Create children for (int i = 0; i < 5; i++) { pids[i] = fork(); if (pids[i] == 0) { sleep(i + 1); exit(i); } } // Wait for specific child printf("Waiting for child with PID %d...\n", pids[2]); int status; pid_t ret = waitpid(pids[2], &status, 0); if (ret == pids[2]) { printf("Child %d finished with status %d\n", ret, WEXITSTATUS(status)); } // Wait for any child (non-blocking) while ((ret = waitpid(-1, &status, WNOHANG)) > 0) { printf("Child %d finished\n", ret); } // Wait for remaining children while (wait(NULL) > 0); } 2. Process Status and Resource Usage
#include <sys/time.h> #include <sys/resource.h> #include <sys/wait.h> void monitor_child_resources(pid_t pid) { int status; struct rusage usage; pid_t ret = wait4(pid, &status, 0, &usage); if (ret != -1) { printf("Child %d resource usage:\n", pid); printf(" User CPU time: %ld.%06ld seconds\n", usage.ru_utime.tv_sec, usage.ru_utime.tv_usec); printf(" System CPU time: %ld.%06ld seconds\n", usage.ru_stime.tv_sec, usage.ru_stime.tv_usec); printf(" Page faults (reclaimable): %ld\n", usage.ru_minflt); printf(" Page faults (unreclaimable): %ld\n", usage.ru_majflt); printf(" Voluntary context switches: %ld\n", usage.ru_nvcsw); printf(" Involuntary context switches: %ld\n", usage.ru_nivcsw); } } Orphan and Zombie Processes
1. Zombie Process Demonstration
#include <stdio.h> #include <unistd.h> #include <sys/wait.h> #include <stdlib.h> void create_zombie() { pid_t pid = fork(); if (pid == 0) { // Child exits immediately printf("Child (PID=%d) exiting\n", getpid()); exit(0); } else { // Parent sleeps without waiting printf("Parent (PID=%d) sleeping. Child %d is zombie\n", getpid(), pid); printf("Run 'ps aux | grep Z' to see zombie process\n"); sleep(30); // Now wait to clean up zombie wait(NULL); printf("Parent waited, zombie cleaned up\n"); } } 2. Orphan Process and init Adoption
#include <stdio.h> #include <unistd.h> #include <stdlib.h> void create_orphan() { pid_t pid = fork(); if (pid == 0) { // Child process printf("Child (PID=%d, PPID=%d) started\n", getpid(), getppid()); // Parent will exit, making this an orphan sleep(5); printf("After parent exit: Child (PID=%d, PPID=%d)\n", getpid(), getppid()); printf("Child adopted by init (PID=1)\n"); exit(0); } else { // Parent exits immediately printf("Parent (PID=%d) exiting\n", getpid()); exit(0); } } Process Daemonization
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/stat.h> #include <fcntl.h> #include <signal.h> void daemonize() { pid_t pid; // Fork and exit parent pid = fork(); if (pid < 0) { perror("fork"); exit(1); } if (pid > 0) { exit(0); // Parent exits } // Child becomes session leader if (setsid() < 0) { perror("setsid"); exit(1); } // Ignore terminal I/O signals signal(SIGCHLD, SIG_IGN); signal(SIGHUP, SIG_IGN); // Fork again to ensure not session leader pid = fork(); if (pid < 0) { perror("fork"); exit(1); } if (pid > 0) { exit(0); } // Change working directory chdir("/"); // Clear file mode creation mask umask(0); // Close all open file descriptors for (int i = 0; i < sysconf(_SC_OPEN_MAX); i++) { close(i); } // Redirect stdin, stdout, stderr to /dev/null open("/dev/null", O_RDWR); dup(0); dup(0); } void run_daemon() { daemonize(); // Daemon code here FILE *log = fopen("/tmp/mydaemon.log", "a"); if (log) { for (int i = 0; i < 10; i++) { fprintf(log, "Daemon running: iteration %d\n", i); fflush(log); sleep(5); } fclose(log); } } Process Groups and Sessions
#include <stdio.h> #include <unistd.h> #include <signal.h> #include <sys/wait.h> void demonstrate_process_groups() { pid_t pid; printf("Parent: PID=%d, PGID=%d, SID=%d\n", getpid(), getpgrp(), getsid(0)); for (int i = 0; i < 3; i++) { pid = fork(); if (pid == 0) { // Child printf("Child %d: PID=%d, PGID=%d, SID=%d\n", i, getpid(), getpgrp(), getsid(0)); // Create new process group if (i == 1) { setpgid(0, 0); printf("Child %d created new process group: PGID=%d\n", i, getpgrp()); } sleep(5); exit(0); } } // Send signal to specific process group sleep(2); printf("Sending SIGTERM to process group of child 1...\n"); killpg(getpgid(pid), SIGTERM); // Wait for children while (wait(NULL) > 0); } Inter-Process Communication (IPC)
1. Pipes
#include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/wait.h> void pipe_communication() { int pipefd[2]; char buffer[256]; if (pipe(pipefd) == -1) { perror("pipe"); return; } pid_t pid = fork(); if (pid == 0) { // Child: writer close(pipefd[0]); // Close read end char *message = "Hello from child!"; write(pipefd[1], message, strlen(message) + 1); close(pipefd[1]); exit(0); } else { // Parent: reader close(pipefd[1]); // Close write end read(pipefd[0], buffer, sizeof(buffer)); printf("Parent received: %s\n", buffer); close(pipefd[0]); wait(NULL); } } void bidirectional_pipe() { int pipe1[2], pipe2[2]; if (pipe(pipe1) == -1 || pipe(pipe2) == -1) { perror("pipe"); return; } pid_t pid = fork(); if (pid == 0) { // Child close(pipe1[1]); // Close write end of pipe1 close(pipe2[0]); // Close read end of pipe2 char msg[256]; read(pipe1[0], msg, sizeof(msg)); printf("Child received: %s\n", msg); char *reply = "Reply from child"; write(pipe2[1], reply, strlen(reply) + 1); close(pipe1[0]); close(pipe2[1]); exit(0); } else { // Parent close(pipe1[0]); // Close read end of pipe1 close(pipe2[1]); // Close write end of pipe2 char *msg = "Hello from parent"; write(pipe1[1], msg, strlen(msg) + 1); char reply[256]; read(pipe2[0], reply, sizeof(reply)); printf("Parent received: %s\n", reply); close(pipe1[1]); close(pipe2[0]); wait(NULL); } } 2. Named Pipes (FIFOs)
#include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <unistd.h> #include <string.h> #define FIFO_NAME "/tmp/myfifo" void fifo_writer() { mkfifo(FIFO_NAME, 0666); int fd = open(FIFO_NAME, O_WRONLY); if (fd == -1) { perror("open"); return; } char *message = "Hello through FIFO!"; write(fd, message, strlen(message) + 1); close(fd); } void fifo_reader() { int fd = open(FIFO_NAME, O_RDONLY); if (fd == -1) { perror("open"); return; } char buffer[256]; read(fd, buffer, sizeof(buffer)); printf("Reader received: %s\n", buffer); close(fd); unlink(FIFO_NAME); } 3. Shared Memory
#include <sys/ipc.h> #include <sys/shm.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/wait.h> #define SHM_SIZE 1024 void shared_memory_demo() { int shmid; char *shm_ptr; // Create shared memory segment shmid = shmget(IPC_PRIVATE, SHM_SIZE, IPC_CREAT | 0666); if (shmid == -1) { perror("shmget"); return; } pid_t pid = fork(); if (pid == 0) { // Child: attach and write shm_ptr = shmat(shmid, NULL, 0); if (shm_ptr == (char*)-1) { perror("shmat"); return; } strcpy(shm_ptr, "Message from child"); printf("Child wrote: %s\n", shm_ptr); shmdt(shm_ptr); exit(0); } else { // Parent: attach and read wait(NULL); shm_ptr = shmat(shmid, NULL, 0); if (shm_ptr == (char*)-1) { perror("shmat"); return; } printf("Parent read: %s\n", shm_ptr); shmdt(shm_ptr); // Remove shared memory shmctl(shmid, IPC_RMID, NULL); } } Process Scheduling and Priorities
#include <sched.h> #include <sys/resource.h> #include <errno.h> void demonstrate_process_priorities() { // Get current priority int priority = getpriority(PRIO_PROCESS, 0); printf("Current priority: %d\n", priority); // Set higher priority (requires root) if (setpriority(PRIO_PROCESS, 0, -10) == 0) { printf("Priority increased to -10\n"); } else if (errno == EPERM) { printf("Need root to increase priority\n"); } // Get scheduling policy int policy = sched_getscheduler(0); switch(policy) { case SCHED_FIFO: printf("Scheduling: FIFO (real-time)\n"); break; case SCHED_RR: printf("Scheduling: Round Robin (real-time)\n"); break; case SCHED_OTHER: printf("Scheduling: Normal (time-sharing)\n"); break; default: printf("Scheduling: Unknown\n"); } // Set real-time scheduling (requires root) struct sched_param param; param.sched_priority = 1; if (sched_setscheduler(0, SCHED_FIFO, ¶m) == 0) { printf("Set real-time scheduling\n"); } } Process Limits
#include <sys/resource.h> #include <errno.h> void demonstrate_process_limits() { struct rlimit limit; // Get core file size limit getrlimit(RLIMIT_CORE, &limit); printf("Core file size: soft=%lu, hard=%lu\n", limit.rlim_cur, limit.rlim_max); // Get CPU time limit getrlimit(RLIMIT_CPU, &limit); printf("CPU time: soft=%lu, hard=%lu\n", limit.rlim_cur, limit.rlim_max); // Get file size limit getrlimit(RLIMIT_FSIZE, &limit); printf("File size: soft=%lu, hard=%lu\n", limit.rlim_cur, limit.rlim_max); // Get open files limit getrlimit(RLIMIT_NOFILE, &limit); printf("Open files: soft=%lu, hard=%lu\n", limit.rlim_cur, limit.rlim_max); // Get process count limit getrlimit(RLIMIT_NPROC, &limit); printf("Processes: soft=%lu, hard=%lu\n", limit.rlim_cur, limit.rlim_max); // Set new limit (if allowed) limit.rlim_cur = 1024; if (setrlimit(RLIMIT_NOFILE, &limit) == 0) { printf("Open files limit increased to %lu\n", limit.rlim_cur); } } Complete Example: Process Manager
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <signal.h> #include <sys/wait.h> #define MAX_PROCESSES 100 #define MAX_CMD_LEN 256 typedef struct { pid_t pid; char command[MAX_CMD_LEN]; int status; // 0: running, 1: stopped, 2: terminated } ProcessInfo; ProcessInfo processes[MAX_PROCESSES]; int process_count = 0; void add_process(pid_t pid, const char *cmd) { if (process_count < MAX_PROCESSES) { processes[process_count].pid = pid; strncpy(processes[process_count].command, cmd, MAX_CMD_LEN - 1); processes[process_count].status = 0; process_count++; } } void remove_process(pid_t pid) { for (int i = 0; i < process_count; i++) { if (processes[i].pid == pid) { for (int j = i; j < process_count - 1; j++) { processes[j] = processes[j + 1]; } process_count--; break; } } } void list_processes() { printf("\n%-10s %-20s %-10s\n", "PID", "COMMAND", "STATUS"); printf("----------------------------------------\n"); for (int i = 0; i < process_count; i++) { const char *status_str; switch (processes[i].status) { case 0: status_str = "Running"; break; case 1: status_str = "Stopped"; break; case 2: status_str = "Terminated"; break; default: status_str = "Unknown"; } printf("%-10d %-20s %-10s\n", processes[i].pid, processes[i].command, status_str); } printf("\n"); } void kill_process(pid_t pid, int signal) { if (kill(pid, signal) == 0) { printf("Signal %d sent to process %d\n", signal, pid); if (signal == SIGTERM || signal == SIGKILL) { // Mark for removal (will be cleaned up on wait) } } else { perror("kill"); } } void background_execute(char *cmd) { pid_t pid = fork(); if (pid == 0) { // Child process char *args[] = {"/bin/sh", "-c", cmd, NULL}; execvp("/bin/sh", args); perror("execvp"); exit(1); } else if (pid > 0) { // Parent process add_process(pid, cmd); printf("[%d] %d\n", process_count, pid); } else { perror("fork"); } } void foreground_execute(char *cmd) { pid_t pid = fork(); if (pid == 0) { // Child process char *args[] = {"/bin/sh", "-c", cmd, NULL}; execvp("/bin/sh", args); perror("execvp"); exit(1); } else if (pid > 0) { // Parent process - wait for child add_process(pid, cmd); int status; waitpid(pid, &status, 0); remove_process(pid); } else { perror("fork"); } } void reap_zombies() { int status; pid_t pid; while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { printf("Process %d terminated\n", pid); remove_process(pid); } } void signal_handler(int sig) { printf("\nReceived signal %d\n", sig); reap_zombies(); } int main() { char input[MAX_CMD_LEN]; // Set up signal handler signal(SIGCHLD, signal_handler); signal(SIGINT, signal_handler); printf("Process Manager\n"); printf("Commands:\n"); printf(" <command> & - Run in background\n"); printf(" <command> - Run in foreground\n"); printf(" jobs - List processes\n"); printf(" kill <pid> - Terminate process\n"); printf(" kill -9 <pid> - Force kill process\n"); printf(" exit - Exit\n\n"); while (1) { printf("pm> "); fflush(stdout); if (fgets(input, sizeof(input), stdin) == NULL) { break; } // Remove newline input[strcspn(input, "\n")] = 0; if (strlen(input) == 0) { continue; } if (strcmp(input, "exit") == 0) { break; } else if (strcmp(input, "jobs") == 0) { list_processes(); } else if (strncmp(input, "kill", 4) == 0) { int sig = SIGTERM; pid_t pid; if (strncmp(input, "kill -9", 7) == 0) { sig = SIGKILL; pid = atoi(input + 7); } else { pid = atoi(input + 4); } if (pid > 0) { kill_process(pid, sig); } } else { // Check for background execution int len = strlen(input); if (len > 0 && input[len - 1] == '&') { input[len - 1] = '\0'; background_execute(input); } else { foreground_execute(input); } } reap_zombies(); } // Clean up all processes for (int i = 0; i < process_count; i++) { kill(processes[i].pid, SIGTERM); } return 0; } Best Practices Summary
| Practice | Why It Matters |
|---|---|
| Always check fork() return value | fork can fail |
| Handle child processes with wait() | Prevents zombies |
| Use _exit() in child after fork | Avoids flushing stdio buffers twice |
| Set up signal handlers | Handle SIGCHLD, SIGINT, SIGTERM |
| Close unused pipe ends | Prevents resource leaks |
| Check exec() return | exec only returns on error |
| Use volatile sig_atomic_t | For variables modified in signal handlers |
| Daemonize properly | Fork twice, close file descriptors |
| Monitor resource usage | Detect memory leaks, CPU issues |
| Document process behavior | Helps maintainers understand IPC |
Conclusion
Process management in C provides the foundation for building sophisticated, multi-process applications. From simple process creation with fork() to complex inter-process communication with pipes and shared memory, these tools enable developers to harness the full power of modern operating systems.
Key takeaways:
- Understand process lifecycle: Creation, execution, termination
- Handle child processes properly: Prevent zombies, reap properly
- Choose appropriate IPC: Pipes for simple, shared memory for performance
- Set up signal handlers: Graceful shutdown, child reaping
- Consider security: Drop privileges, sanitize inputs
- Monitor resources: Track usage, set appropriate limits
By mastering process management, you can build robust, scalable, and efficient C applications that leverage multiple processes for improved performance, isolation, and reliability.
Complete C Programming Guide + Compilers Collection
1. C srand() Function – Understanding Seed Initialization
https://macronepal.com/understanding-the-c-srand-function
Explains how srand() initializes the pseudo-random number generator in C by setting a seed value. Using the same seed produces the same sequence, while time(NULL) gives different results each run.
2. C rand() Function Mechanics and Limitations
https://macronepal.com/c-rand-function-mechanics-and-limitations
Explains how rand() generates pseudo-random numbers between 0 and RAND_MAX, its deterministic nature, and limitations for security use cases.
3. C log() Function
https://macronepal.com/c-log-function-2
Covers natural logarithm calculation using <math.h> and its applications.
4. Mastering Date and Time in C
https://macronepal.com/mastering-date-and-time-in-c
Explains <time.h> functions like time(), clock(), difftime(), and struct tm.
5. Mastering time_t Type in C
https://macronepal.com/mastering-the-c-time_t-type-for-time-management
Explains time representation as seconds since Unix epoch and conversion functions.
6. C exp() Function
https://macronepal.com/c-exp-function-mechanics-and-implementation
Explains exponential function exp(x) and its scientific applications.
7. C log() Function (Alternate Guide)
https://macronepal.com/c-log-function
Comparison of log() and log10() with usage examples.
8. C log10() Function
https://macronepal.com/mastering-the-log10-function-in-c
Explains base-10 logarithm for engineering and scientific applications.
9. C tan() Function
https://macronepal.com/understanding-the-c-tan-function
Explains tangent function and radian-based calculations.
10. Random Numbers in C (Secure vs Predictable)
https://macronepal.com/mastering-c-random-numbers-for-secure-and-predictable-applications
Explains difference between rand() and secure randomness methods.
11. Free Online C Compiler
https://macronepal.com/free-online-c-code-compiler-2
Browser-based compiler for testing C programs instantly.
C Functions, Arguments, Parameters & Flow
Mastering Functions in C – Complete Guide
https://macronepal.com/c/mastering-functions-in-c-a-complete-guide/
Covers function structure, modular programming, and real-world usage.
Function Arguments in C
https://macronepal.com/c-function-arguments/
Explains how arguments are passed and used in function calls.
Function Parameters in C
https://macronepal.com/c-function-parameters/
Explains defining inputs for functions and matching them with arguments.
Function Declarations in C
https://macronepal.com/c-function-declarations-syntax-rules-and-best-practices/
Covers prototypes, syntax rules, and best practices.
Function Calls in C
https://macronepal.com/understanding-function-calls-in-c-syntax-mechanics-and-best-practices/
Explains execution flow and parameter handling during function calls.
Void Functions in C
https://macronepal.com/understanding-void-functions-in-c-syntax-patterns-and-best-practices/
Explains functions that do not return values.
Return Values in C
https://macronepal.com/c-return-values-mechanics-types-and-best-practices/
Explains different return types and how functions return results.
Pass-by-Value in C
https://macronepal.com/aws/understanding-pass-by-value-in-c-mechanics-implications-and-best-practices/
Explains how copies of variables are passed into functions.
Pass-by-Reference in C
https://macronepal.com/c/understanding-pass-by-reference-in-c-pointers-semantics-and-safe-practices/
Explains using pointers to modify original variables.
C strstr() Function
https://macronepal.com/aws/c-strstr-function/
Explains substring search inside strings in C.
C Preprocessor & Macros
https://macronepal.com/mastering-c-variadic-macros-for-flexible-debugging/
https://macronepal.com/mastering-the-stdc-macro-in-c/
https://macronepal.com/c-time-macro-mechanics-and-usage/
https://macronepal.com/understanding-the-c-date-macro/
https://macronepal.com/c-file-type/
https://macronepal.com/mastering-c-line-macro-for-debugging-and-diagnostics/
https://macronepal.com/mastering-predefined-macros-in-c/
https://macronepal.com/c-error-directive-mechanics-and-usage/
https://macronepal.com/understanding-the-c-pragma-directive/
https://macronepal.com/c-include-directive/
C Structures, Memory, Scope & Linkage
https://macronepal.com/mastering-structures-in-c/
https://macronepal.com/c-structure-declaration-mechanics-and-usage/
https://macronepal.com/c-structure-initialization-mechanics-and-best-practices/
https://macronepal.com/mastering-c-structure-member-access-for-reliable-data-handling/
https://macronepal.com/c-nested-structures/
https://macronepal.com/mastering-arrays-of-structures-in-c/
https://macronepal.com/c-structure-pointers-mechanics-and-implementation/
https://macronepal.com/understanding-c-structure-parameter-passing-mechanics/
https://macronepal.com/mastering-c-returning-structures-for-efficient-data-flow/
https://macronepal.com/c-self-referential-structures/
https://macronepal.com/mastering-structure-alignment-in-c/
https://macronepal.com/c-structure-padding-mechanics-and-optimization/
https://macronepal.com/understanding-c-flexible-array-members-mechanics-and-usage/
https://macronepal.com/mastering-c-anonymous-structures-for-flattened-data-layouts/
https://macronepal.com/c-unions/
https://macronepal.com/mastering-c-name-mangling-and-symbol-decoration/
https://macronepal.com/c-no-linkage-mechanics-and-scope-isolation/
https://macronepal.com/understanding-c-internal-linkage-mechanics-and-architecture/
C Scope, Storage Classes & Typedef
https://macronepal.com/mastering-function-prototype-scope-in-c/
https://macronepal.com/c-function-scope-mechanics-and-visibility/
https://macronepal.com/understanding-c-file-scope-mechanics-and-architecture/
https://macronepal.com/mastering-c-scope-rules-for-predictable-name-resolution/
https://macronepal.com/c-scope-rules/
https://macronepal.com/mastering-c-register-storage-class-for-historical-context-and-modern-alternatives/
https://macronepal.com/mastering-_thread_local-in-c/
https://macronepal.com/c-extern-storage-class-mechanics-and-usage/
https://macronepal.com/understanding-the-c-static-storage-class-mechanics-and-usage/
https://macronepal.com/c-auto-storage-class/
https://macronepal.com/c-typedef-with-pointers/
Extra Articles
https://macronepal.com/13757-2/
https://macronepal.com/13748-2/
https://macronepal.com/13747-2/
https://macronepal.com/13746-2/
https://macronepal.com/13745-2/
https://macronepal.com/13708-2/
https://macronepal.com/13707-2/
https://macronepal.com/13702-2/
Online Compilers
https://macronepal.com/free-html-online-code-compiler/
https://macronepal.com/free-online-python-code-compiler/
https://macronepal.com/free-online-python2-code-compiler/
https://macronepal.com/free-online-java-code-compiler/
https://macronepal.com/free-online-javascript-code-compiler/
https://macronepal.com/free-online-node-js-code-compiler/
https://macronepal.com/free-online-c-code-compiler/
https://macronepal.com/free-online-c-code-compiler-2/
https://macronepal.com/free-online-c-code-compiler-3/
https://macronepal.com/free-online-php-code-compiler/
https://macronepal.com/free-online-ruby-code-compiler/
https://macronepal.com/free-online-perl-code-compiler/
https://macronepal.com/free-online-lua-code-compiler/
https://macronepal.com/free-online-tcl-code-compiler/
https://macronepal.com/free-online-groovy-code-compiler/
https://macronepal.com/free-online-j-shell-code-compiler/
https://macronepal.com/free-online-haskell-code-compiler/
https://macronepal.com/free-online-scala-code-compiler/
https://macronepal.com/free-online-common-lisp-code-compiler/
https://macronepal.com/free-online-d-code-compiler/
https://macronepal.com/free-online-ada-code-compiler/
https://macronepal.com/free-erlang-code-compiler/
https://macronepal.com/free-online-assembly-code-compiler/
Complete Guide to Advanced C Programming, Systems, GPU, Kernel & Parallel Computing
https://macronepal.com/bash/the-building-blocks-of-c-a-complete-guide-to-variables-and-data-types/
Explains variables and data types in C, including how different types define memory usage, value range, and program data handling.
https://macronepal.com/bash/hello-world-in-c-the-program-that-started-it-all/
Explains the basic “Hello World” program in C, covering program structure, main function, and output printing.
https://macronepal.com/bash/advanced-i-o-operations-in-c-mastering-input-output-for-high-performance-applications/
Explains advanced input/output operations in C, including efficient data handling and file-based I/O for high-performance applications.
https://macronepal.com/bash/harnessing-massive-parallelism-a-complete-guide-to-gpu-programming-in-c/
Explains GPU programming in C for massive parallel processing, enabling faster computation for complex workloads.
https://macronepal.com/bash/understanding-the-unseen-a-complete-guide-to-reverse-engineering-c-programs/
Explains reverse engineering of C programs by analyzing compiled binaries to understand program behavior and logic.
https://macronepal.com/bash/protecting-intellectual-property-a-complete-guide-to-code-obfuscation-in-c/
Explains code obfuscation techniques in C to protect source code and make reverse engineering difficult.
https://macronepal.com/bash/kernel-programming-in-c-a-comprehensive-guide-to-linux-kernel-development/
Explains Linux kernel programming in C, focusing on low-level system operations and kernel module development.
https://macronepal.com/bash/kernel-programming-a-complete-guide-to-writing-device-drivers-in-c/
Explains how to write device drivers in C for Linux, enabling communication between hardware and the operating system.
https://macronepal.com/bash/parallel-data-processing-a-complete-guide-to-simd-programming-in-c/
Explains SIMD programming in C for processing multiple data points in parallel using a single instruction.
https://macronepal.com/bash/harnessing-multi-core-power-a-complete-guide-to-parallel-programming-in-c/
Explains multi-core parallel programming in C by distributing tasks across threads to improve performance and efficiency.
