Steam Achievement Manager终极指南:简单快速成就管理解决方案
2026/6/14 11:03:12
在 Linux 系统编程中,进程创建与控制是核心知识点。本文将详细讲解exec族函数(进程程序替换)、waitpid(子进程回收)、system(Shell 命令执行)以及getcwd/chdir(目录操作),结合内存原理、函数用法和实际案例,帮你彻底掌握这些关键接口。
exec族函数的核心作用是替换当前进程的代码段和数据段,执行系统中另一个可执行文件。
fork搭配使用:父进程fork创建子进程,子进程通过exec替换为目标程序,父进程负责回收子进程资源。| 阶段 | 内存状态 |
|---|---|
| exec 执行前 | 进程内存包含原程序的代码段、数据段、堆栈 |
| exec 执行后 | 原程序代码段、数据段被新程序替换,堆栈重新初始化 |
exec族函数命名有规律:l(list 参数)、v(vector 数组参数)、p(PATH 环境变量查找),核心区别如下:
| 函数原型 | 关键参数说明 | 核心特点 |
|---|---|---|
int execl(const char *path, const char *arg, ...); | path:新程序路径 + 文件名(如/bin/ls);arg:参数列表(第一个参数通常是程序名,最后必须以NULL结尾) | 参数逐个列出,直观简单 |
int execlp(const char *file, const char *arg, ...); | file:新程序文件名(如ls);系统自动在PATH环境变量路径中查找程序 | 无需写全路径,依赖环境变量 |
int execv(const char *path, char *const argv[]); | path:新程序路径 + 文件名;argv:参数数组(最后一个元素必须是NULL) | 参数存放在数组中,适合参数数量不确定的场景 |
int execvp(const char *file, char *const argv[]); | file:新程序文件名;argv:参数数组;自动在PATH中查找 | 无路径 + 数组参数,最灵活常用 |
exec函数执行成功后不会返回(代码段已被替换);若返回,则表示执行失败(返回-1)。exec函数,第一个参数(path或file)都需写完整路径 + 文件名(如./myprogram),因为自定义程序通常不在PATH中。c
运行
fork创建的子进程若不回收,会变成僵尸进程(占用 PID 资源),waitpid是回收子进程的核心函数(wait是waitpid的简化版,waitpid(-1, status, 0) == wait(status))。
c
运行
pid_t waitpid(pid_t pid, int *status, int options);| 参数 | 取值与含义 |
|---|---|
pid | --1:回收所有子进程(等同于wait);- 正数:回收指定 PID 的子进程;-0:回收与当前进程同组的子进程;- 负数:回收进程组 ID 为-pid的子进程 |
status | - 非 NULL:存储子进程退出状态(需通过宏解析);- NULL:不关注退出状态 |
options | -0:阻塞模式(父进程暂停执行,直到有子进程退出);-WNOHANG:非阻塞模式(父进程不等待,立即返回) |
| 返回值 | 含义 |
|---|---|
| 正数 | 成功回收的子进程 PID |
0 | options=WNOHANG时,没有子进程退出(需再次尝试回收) |
-1 | 错误(如无子进程可回收,errno 会被设置) |
通过以下宏解析子进程退出状态:
WIFEXITED(status):子进程是否正常退出(返回非 0 为正常);WEXITSTATUS(status):获取正常退出的状态码(仅WIFEXITED为真时有效);WIFSIGNALED(status):子进程是否被信号终止(返回非 0 为是);WTERMSIG(status):获取终止子进程的信号编号。system函数封装了fork+exec+waitpid,直接执行一个 Shell 命令(如ls -l、mkdir test),无需手动创建子进程和回收。
c
运行
int system(const char *command);command:要执行的 Shell 命令字符串(如"ls -l"、"rm -rf temp.txt");-1表示执行失败(如 fork 失败);其他值为命令执行结果(需结合waitpid状态解析)。system执行的命令运行在子 Shell 中,无法修改父进程的状态(如环境变量、工作目录);fork+exec;system(可能导致信号阻塞问题)。c
运行
c
运行
char *getcwd(char *buf, size_t size);buf:存储当前路径的字符数组;size:buf的最大长度(需足够容纳路径,包括末尾的\0);buf指针,失败返回NULL(如buf长度不足)。c
运行
#include <stdio.h> #include <unistd.h> #include <stdlib.h> int main() { char buf[1024]; // 定义足够大的缓冲区 if (getcwd(buf, sizeof(buf)) == NULL) { perror("getcwd failed"); exit(1); } printf("当前工作路径:%s\n", buf); return 0; }c
运行
int chdir(const char *path);path:目标路径(绝对路径如/home/user,相对路径如../test);0,失败返回-1(如路径不存在)。c
运行
#include <stdio.h> #include <unistd.h> #include <stdlib.h> int main() { char buf[1024]; // 获取初始路径 getcwd(buf, sizeof(buf)); printf("初始路径:%s\n", buf); // 切换到/home目录(需根据实际系统调整路径) if (chdir("/home") == -1) { perror("chdir failed"); exit(1); } // 获取切换后路径 getcwd(buf, sizeof(buf)); printf("切换后路径:%s\n", buf); return 0; }fork搭配使用,执行成功不返回;fork+exec+waitpid,无法修改父进程状态;chdir仅影响当前进程(子进程不继承)。