进程管理

一、进程基础

pid_t pid = getpid();
pid_t ppid = getppid();
uid_t uid = getuid(), euid = geteuid();
gid_t gid = getgid(), egid = getegid();

进程状态(D 不可中断睡眠 / R 运行 / S 可中断睡眠 / T 停止 / Z 僵尸 / X 死亡 / I 空闲)
查看:ps -eftop/proc/<pid>/status

二、fork / exec / wait

1. fork

#include <sys/wait.h>
#include <unistd.h>

pid_t pid = fork();
if (pid < 0) { perror("fork"); }
else if (pid == 0) {
    // 子进程
    printf("child pid=%d\n", getpid());
    execlp("ls", "ls", "-l", NULL);    // 替换为 ls
    _exit(127);
} else {
    // 父进程
    int status;
    waitpid(pid, &status, 0);
    if (WIFEXITED(status)) {
        printf("exit code = %d\n", WEXITSTATUS(status));
    } else if (WIFSIGNALED(status)) {
        printf("killed by sig %d\n", WTERMSIG(status));
    }
}

2. exec 系列

execl(path, arg0, arg1, ..., NULL)        // 列表
execv(path, argv)                         // 数组
execlp(file, arg0, ..., NULL)             // 找 PATH
execvp(file, argv)                        // 找 PATH
execve(path, argv, envp)                  // 系统调用封装
execle(path, arg0, ..., NULL, envp)

注意:exec 成功则不返回;失败返回 -1。

3. vfork(极少用)

4. wait / waitpid

pid_t wait(int *status);                            // 等任意子进程
pid_t waitpid(pid_t pid, int *status, int options); // 指定 pid
// options: WNOHANG 不阻塞、WUNTRACED 等停止态、WCONTINUED 等继续态

5. SIGCHLD

三、退出

exit(0);           // 退出前调用 atexit 注册函数、刷新 stdio、调用 _exit
_exit(0);          // 立即退出(fork 后子进程常用)
atexit(handler);   // 注册退出处理

四、守护进程

1. 经典五步

1. fork + 父退出                // 让 shell 以为任务完成
2. setsid()                       // 创建新会话,脱离控制终端
3. 再次 fork可选              // 防止重新获得控制终端
4. chdir("/")                     // 防止占用挂载点
5. umask(0)
6. close(0,1,2)  重定向到 /dev/null / 日志文件

2. systemd 时代

五、进程资源

1. 优先级

2. 资源限制

struct rlimit lim = { .rlim_cur = 64*1024*1024, .rlim_max = RLIM_INFINITY };
setrlimit(RLIMIT_AS, &lim);
资源 含义
RLIMIT_CPU CPU 秒
RLIMIT_FSIZE 文件大小
RLIMIT_NOFILE fd 数量
RLIMIT_AS 虚拟内存
RLIMIT_NPROC 进程数
RLIMIT_CORE core 文件大小

3. Cgroup(嵌入式关注)

六、进程间关系

七、代码模板

1. 安全的 fork + exec

static int run_cmd(char *const argv[]) {
    pid_t pid = fork();
    if (pid < 0) return -1;
    if (pid == 0) {
        execvp(argv[0], argv);
        _exit(127);
    }
    int status;
    waitpid(pid, &status, 0);
    return WIFEXITED(status) ? WEXITSTATUS(status) : -1;
}

2. 多客户端服务(fork 模型)

while (1) {
    int cfd = accept(lfd, NULL, NULL);
    if (fork() == 0) {
        close(lfd);
        handle(cfd);
        close(cfd);
        _exit(0);
    }
    close(cfd);
}

注意:fork 模型资源开销大、信号复杂,现代多用单进程多线程 / epoll。