waitid函数详解 链接到标题
1. 函数介绍 链接到标题
waitid函数是Linux系统中用于等待子进程状态变化的高级进程控制函数。它是wait()和waitpid()函数的增强版本,提供了更灵活和详细的功能。可以把waitid想象成一个"进程状态监视器",它能够精确地监控指定子进程或进程组的各种状态变化。
与传统的wait函数相比,waitid提供了更多的控制选项和更丰富的状态信息。它不仅能够等待子进程结束,还能监控子进程的暂停、继续等状态变化,返回详细的状态信息,包括退出状态、信号信息等。
使用场景:
- 多进程程序中的子进程管理
- 服务器程序中的子进程监控
- 系统工具和shell的进程控制
- 调试和测试程序中的进程跟踪
- 实现进程池和作业控制
2. 函数原型 链接到标题
#include <sys/wait.h>
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
3. 功能 链接到标题
waitid函数的主要功能是等待指定进程或进程组的状态变化,并返回详细的状态信息。它支持多种等待模式和选项,可以精确控制等待行为。
4. 参数 链接到标题
-
idtype: 标识类型
- 类型:idtype_t
- 含义:指定要等待的进程标识类型
- 常用值:
- P_ALL:等待所有子进程
- P_PID:等待指定进程ID的进程
- P_PGID:等待指定进程组ID的进程组
-
id: 进程标识符
- 类型:id_t
- 含义:根据idtype指定的标识符值
- 当idtype为P_PID时,id为进程ID
- 当idtype为P_PGID时,id为进程组ID
- 当idtype为P_ALL时,id被忽略(通常设为0)
-
infop: 状态信息缓冲区
- 类型:siginfo_t*
- 含义:指向siginfo_t结构体的指针,用于返回子进程的详细状态信息
-
options: 等待选项
- 类型:int
- 含义:控制等待行为的标志位组合
- 常用值:
- WEXITED:等待子进程正常退出
- WSTOPPED:等待子进程被信号停止
- WCONTINUED:等待被停止的子进程继续执行
- WNOHANG:非阻塞等待(立即返回)
- WNOWAIT:不回收子进程(可多次等待同一子进程)
5. 返回值 链接到标题
- 成功: 返回0
- 失败: 返回-1,并设置errno错误码
- ECHILD:没有符合条件的子进程
- EINTR:等待被信号中断
- EINVAL:参数无效
6. 相似函数或关联函数 链接到标题
- wait(): 等待子进程结束
- waitpid(): 等待指定子进程
- wait3(): 等待子进程并返回资源使用信息
- wait4(): 等待子进程并返回详细资源使用信息
- fork(): 创建子进程
- kill(): 向进程发送信号
- signal()/sigaction(): 信号处理函数
7. 示例代码 链接到标题
示例1:基础waitid使用 - 等待子进程结束 链接到标题
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
// 信号处理函数
void signal_handler(int sig) {
printf("父进程收到信号 %d\n", sig);
}
// 创建测试子进程
pid_t create_test_child(const char* name, int exit_code) {
pid_t pid = fork();
if (pid == -1) {
perror("fork失败");
return -1;
}
if (pid == 0) {
// 子进程
printf("子进程 %s (PID: %d) 启动\n", name, getpid());
sleep(2); // 模拟工作
printf("子进程 %s 准备退出,退出码: %d\n", name, exit_code);
exit(exit_code);
}
// 父进程返回子进程PID
return pid;
}
// 解析siginfo_t信息
void parse_siginfo(const siginfo_t* info) {
printf("子进程状态信息:\n");
printf(" 进程ID: %d\n", info->si_pid);
printf(" 信号码: %d\n", info->si_signo);
printf(" 错误码: %d\n", info->si_errno);
printf(" 信号值: %d\n", info->si_code);
switch (info->si_code) {
case CLD_EXITED:
printf(" 状态: 正常退出,退出码: %d\n", info->si_status);
break;
case CLD_KILLED:
printf(" 状态: 被信号杀死,信号: %d (%s)\n",
info->si_status, strsignal(info->si_status));
break;
case CLD_DUMPED:
printf(" 状态: 被信号杀死并产生core dump,信号: %d (%s)\n",
info->si_status, strsignal(info->si_status));
break;
case CLD_STOPPED:
printf(" 状态: 被信号停止,信号: %d (%s)\n",
info->si_status, strsignal(info->si_status));
break;
case CLD_CONTINUED:
printf(" 状态: 继续执行\n");
break;
default:
printf(" 状态: 未知 (%d)\n", info->si_code);
break;
}
}
int main() {
printf("=== 基础waitid使用示例 ===\n");
// 设置信号处理
signal(SIGINT, signal_handler);
// 创建多个测试子进程
printf("1. 创建测试子进程:\n");
pid_t child1 = create_test_child("Child1", 0);
pid_t child2 = create_test_child("Child2", 42);
pid_t child3 = create_test_child("Child3", 1);
if (child1 == -1 || child2 == -1 || child3 == -1) {
exit(EXIT_FAILURE);
}
printf("创建了3个子进程: %d, %d, %d\n", child1, child2, child3);
// 使用waitid等待所有子进程结束
printf("\n2. 使用waitid等待子进程结束:\n");
siginfo_t info;
int finished_children = 0;
while (finished_children < 3) {
// 等待任意子进程结束
if (waitid(P_ALL, 0, &info, WEXITED) == -1) {
if (errno == EINTR) {
printf("等待被信号中断,继续等待...\n");
continue;
} else {
perror("waitid失败");
break;
}
}
printf("\n检测到子进程状态变化:\n");
parse_siginfo(&info);
finished_children++;
}
printf("\n所有子进程已完成,总计: %d\n", finished_children);
// 演示P_PID用法
printf("\n3. 演示P_PID用法:\n");
pid_t child4 = create_test_child("Child4", 99);
if (child4 != -1) {
// 等待特定子进程
if (waitid(P_PID, child4, &info, WEXITED) == 0) {
printf("等待特定子进程 %d 完成:\n", child4);
parse_siginfo(&info);
} else {
perror("等待特定子进程失败");
}
}
printf("\n=== 基础waitid演示完成 ===\n");
return 0;
}
示例2:waitid高级用法 - 监控进程状态变化 链接到标题
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <time.h>
// 创建可控制的子进程
pid_t create_controllable_child(const char* name) {
pid_t pid = fork();
if (pid == -1) {
perror("fork失败");
return -1;
}
if (pid == 0) {
// 子进程
printf("可控子进程 %s (PID: %d) 启动\n", name, getpid());
// 工作循环
for (int i = 0; i < 10; i++) {
printf("子进程 %s 工作中... (%d/10)\n", name, i + 1);
sleep(1);
}
printf("子进程 %s 正常退出\n", name);
exit(0);
}
return pid;
}
// 发送信号给进程
void send_signal_to_process(pid_t pid, int signal) {
printf("向进程 %d 发送信号 %d (%s)\n", pid, signal, strsignal(signal));
if (kill(pid, signal) == -1) {
perror("发送信号失败");
}
}
// 显示详细状态信息
void show_detailed_status(const siginfo_t* info) {
time_t current_time = time(NULL);
printf("[%s", ctime(¤t_time));
// 移除ctime返回的换行符
char* newline = strchr(ctime(¤t_time), '\n');
if (newline) *newline = '\0';
printf("] 进程 %d 状态变化:\n", info->si_pid);
switch (info->si_code) {
case CLD_EXITED:
printf(" 正常退出,退出状态: %d\n", info->si_status);
break;
case CLD_KILLED:
printf(" 被信号 %d (%s) 杀死\n", info->si_status, strsignal(info->si_status));
break;
case CLD_DUMPED:
printf(" 被信号 %d (%s) 杀死并产生core dump\n",
info->si_status, strsignal(info->si_status));
break;
case CLD_STOPPED:
printf(" 被信号 %d (%s) 停止\n", info->si_status, strsignal(info->si_status));
break;
case CLD_CONTINUED:
printf(" 继续执行\n");
break;
default:
printf(" 未知状态: %d\n", info->si_code);
break;
}
printf(" 用户ID: %d\n", info->si_uid);
printf(" 进程组ID: %d\n", getpgid(info->si_pid));
}
int main() {
printf("=== waitid高级用法示例 ===\n");
// 创建可控子进程
printf("1. 创建可控子进程:\n");
pid_t child = create_controllable_child("MonitorChild");
if (child == -1) {
exit(EXIT_FAILURE);
}
printf("创建子进程 PID: %d\n", child);
// 使用waitid监控所有状态变化
printf("\n2. 监控子进程状态变化:\n");
siginfo_t info;
int monitoring = 1;
int status_changes = 0;
while (monitoring) {
// 非阻塞等待
if (waitid(P_PID, child, &info, WEXITED | WSTOPPED | WCONTINUED | WNOHANG) == -1) {
if (errno == ECHILD) {
printf("子进程已不存在\n");
break;
} else if (errno == EINTR) {
printf("等待被中断\n");
continue;
} else {
perror("waitid失败");
break;
}
}
// 检查是否有状态变化
if (info.si_pid != 0) {
show_detailed_status(&info);
status_changes++;
// 如果子进程退出,停止监控
if (info.si_code == CLD_EXITED ||
info.si_code == CLD_KILLED ||
info.si_code == CLD_DUMPED) {
monitoring = 0;
}
} else {
// 没有状态变化,发送一些控制信号
static int signal_count = 0;
signal_count++;
switch (signal_count) {
case 3:
send_signal_to_process(child, SIGSTOP);
break;
case 6:
send_signal_to_process(child, SIGCONT);
break;
case 9:
send_signal_to_process(child, SIGTERM);
break;
}
sleep(1);
}
}
printf("\n监控结束,总计状态变化: %d 次\n", status_changes);
// 演示P_PGID用法
printf("\n3. 演示P_PGID用法:\n");
// 创建进程组
pid_t group_leader = fork();
if (group_leader == 0) {
// 组长进程
setpgid(0, 0); // 创建新进程组
// 创建组内进程
for (int i = 0; i < 3; i++) {
pid_t member = fork();
if (member == 0) {
setpgid(0, getpid()); // 加入进程组
printf("进程组成员 %d 启动\n", getpid());
sleep(2 + i);
exit(i);
} else {
setpgid(member, getpid());
}
}
// 组长等待所有成员
sleep(5);
exit(0);
}
if (group_leader != -1) {
printf("创建进程组,组长PID: %d\n", group_leader);
sleep(1); // 等待进程组创建完成
// 等待进程组中的任意进程
printf("等待进程组中的进程状态变化:\n");
int group_finished = 0;
while (group_finished < 4) { // 组长 + 3个成员
if (waitid(P_PGID, group_leader, &info, WEXITED | WNOHANG) == 0) {
if (info.si_pid != 0) {
printf("进程组成员 %d 退出,状态: %d\n",
info.si_pid, info.si_status);
group_finished++;
} else {
sleep(1);
}
} else {
if (errno != ECHILD) {
perror("等待进程组失败");
}
break;
}
}
printf("进程组监控完成\n");
}
printf("\n=== 高级waitid演示完成 ===\n");
return 0;
}
示例3:进程池管理与批量等待 链接到标题
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#define MAX_PROCESSES 10
#define POOL_SIZE 5
// 进程信息结构
typedef struct {
pid_t pid;
int job_id;
time_t start_time;
int status;
int finished;
} process_info_t;
process_info_t process_pool[MAX_PROCESSES];
int process_count = 0;
// 创建工作进程
pid_t create_worker_process(int job_id, int work_time) {
pid_t pid = fork();
if (pid == -1) {
perror("创建进程失败");
return -1;
}
if (pid == 0) {
// 工作进程
printf("工作进程 %d (PID: %d) 启动,任务ID: %d\n",
getpid(), getpid(), job_id);
// 模拟工作
for (int i = 0; i < work_time; i++) {
printf("工作进程 %d 执行任务 %d (%d/%d)\n",
getpid(), job_id, i + 1, work_time);
sleep(1);
}
int exit_code = job_id % 100; // 生成退出码
printf("工作进程 %d 完成任务 %d,退出码: %d\n",
getpid(), job_id, exit_code);
exit(exit_code);
}
// 父进程记录进程信息
if (process_count < MAX_PROCESSES) {
process_pool[process_count].pid = pid;
process_pool[process_count].job_id = job_id;
process_pool[process_count].start_time = time(NULL);
process_pool[process_count].status = 0;
process_pool[process_count].finished = 0;
process_count++;
}
return pid;
}
// 显示进程池状态
void show_process_pool_status() {
printf("\n进程池状态 (%d 个进程):\n", process_count);
printf("%-8s %-8s %-10s %-10s %-15s\n",
"PID", "JobID", "状态", "退出码", "运行时间");
printf("%-8s %-8s %-10s %-10s %-15s\n",
"---", "-----", "----", "------", "--------");
time_t current_time = time(NULL);
for (int i = 0; i < process_count; i++) {
const process_info_t* proc = &process_pool[i];
char status_str[16];
char runtime_str[16];
if (proc->finished) {
snprintf(status_str, sizeof(status_str), "完成");
} else {
snprintf(status_str, sizeof(status_str), "运行中");
}
int runtime = current_time - proc->start_time;
snprintf(runtime_str, sizeof(runtime_str), "%ds", runtime);
printf("%-8d %-8d %-10s %-10d %-15s\n",
proc->pid, proc->job_id, status_str,
proc->status, runtime_str);
}
printf("\n");
}
// 批量启动进程
int start_process_pool(int pool_size) {
printf("启动进程池 (大小: %d):\n", pool_size);
for (int i = 0; i < pool_size; i++) {
int work_time = 3 + (i % 4); // 3-6秒的工作时间
pid_t pid = create_worker_process(i + 1, work_time);
if (pid != -1) {
printf("启动工作进程: PID %d (任务 %d)\n", pid, i + 1);
} else {
return -1;
}
}
return 0;
}
// 使用waitid批量等待进程
int wait_for_process_pool() {
printf("开始批量等待进程池中的进程:\n");
siginfo_t info;
int finished_count = 0;
int timeout = 30; // 30秒超时
while (finished_count < process_count && timeout > 0) {
// 非阻塞等待
if (waitid(P_ALL, 0, &info, WEXITED | WNOHANG) == -1) {
if (errno == ECHILD) {
printf("没有子进程可等待\n");
break;
} else if (errno == EINTR) {
printf("等待被中断\n");
continue;
} else {
perror("waitid失败");
break;
}
}
// 检查是否有进程结束
if (info.si_pid != 0) {
printf("进程 %d 结束,退出码: %d\n",
info.si_pid, info.si_status);
// 更新进程池信息
for (int i = 0; i < process_count; i++) {
if (process_pool[i].pid == info.si_pid) {
process_pool[i].finished = 1;
process_pool[i].status = info.si_status;
break;
}
}
finished_count++;
show_process_pool_status();
} else {
// 没有进程结束,等待一段时间
printf("等待进程结束... (%d/%d 完成)\n",
finished_count, process_count);
sleep(1);
timeout--;
}
}
if (timeout <= 0) {
printf("等待超时\n");
return -1;
}
printf("所有进程已完成\n");
return 0;
}
// 清理剩余进程
void cleanup_remaining_processes() {
printf("清理剩余进程:\n");
for (int i = 0; i < process_count; i++) {
if (!process_pool[i].finished) {
printf("终止进程 %d\n", process_pool[i].pid);
kill(process_pool[i].pid, SIGTERM);
}
}
// 等待所有进程结束
siginfo_t info;
while (waitid(P_ALL, 0, &info, WEXITED | WNOHANG) == 0 && info.si_pid != 0) {
printf("进程 %d 已终止\n", info.si_pid);
}
}
int main() {
printf("=== 进程池管理与批量等待示例 ===\n");
// 启动进程池
if (start_process_pool(POOL_SIZE) == -1) {
exit(EXIT_FAILURE);
}
show_process_pool_status();
// 等待进程池中的进程
printf("\n开始等待进程池中的进程:\n");
if (wait_for_process_pool() == -1) {
printf("等待过程中出现问题\n");
cleanup_remaining_processes();
}
show_process_pool_status();
// 演示WNOWAIT选项
printf("\n演示WNOWAIT选项:\n");
// 创建测试进程
pid_t test_pid = fork();
if (test_pid == 0) {
printf("测试进程 %d 启动\n", getpid());
sleep(2);
exit(42);
}
if (test_pid != -1) {
printf("创建测试进程 PID: %d\n", test_pid);
// 第一次等待(使用WNOWAIT)
siginfo_t info1;
if (waitid(P_PID, test_pid, &info1, WEXITED | WNOWAIT) == 0) {
printf("第一次等待结果:\n");
printf(" 进程 %d 退出,状态: %d\n", info1.si_pid, info1.si_status);
}
// 第二次等待(正常等待,回收进程)
siginfo_t info2;
if (waitid(P_PID, test_pid, &info2, WEXITED) == 0) {
printf("第二次等待结果:\n");
printf(" 进程 %d 退出,状态: %d\n", info2.si_pid, info2.si_status);
}
printf("WNOWAIT演示完成\n");
}
// 演示错误处理
printf("\n错误处理演示:\n");
// 等待不存在的进程
siginfo_t info;
if (waitid(P_PID, 999999, &info, WEXITED) == -1) {
if (errno == ECHILD) {
printf("✓ 正确处理了不存在的进程\n");
} else {
printf("✗ 其他错误: %s\n", strerror(errno));
}
}
// 使用无效的idtype
if (waitid((idtype_t)999, 0, &info, WEXITED) == -1) {
if (errno == EINVAL) {
printf("✓ 正确处理了无效的idtype\n");
} else {
printf("✗ 其他错误: %s\n", strerror(errno));
}
}
printf("\n=== 进程池管理演示完成 ===\n");
return 0;
}
示例4:信号处理与进程监控 链接到标题
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#define MAX_MONITORED_PROCESSES 20
// 被监控的进程信息
typedef struct {
pid_t pid;
char name[64];
time_t start_time;
int monitoring;
int stop_signal_sent;
} monitored_process_t;
monitored_process_t monitored_processes[MAX_MONITORED_PROCESSES];
int monitored_count = 0;
volatile sig_atomic_t stop_monitoring = 0;
// 信号处理函数
void signal_handler(int sig) {
printf("\n收到信号 %d (%s)\n", sig, strsignal(sig));
if (sig == SIGINT || sig == SIGTERM) {
stop_monitoring = 1;
printf("开始停止进程监控...\n");
}
}
// 创建长时间运行的进程
pid_t create_long_running_process(const char* name) {
pid_t pid = fork();
if (pid == -1) {
perror("创建进程失败");
return -1;
}
if (pid == 0) {
// 子进程
printf("长时间运行进程 %s (PID: %d) 启动\n", name, getpid());
// 设置进程组
setpgid(0, 0);
// 工作循环
int counter = 0;
while (1) {
counter++;
printf("进程 %s 工作中... (%d)\n", name, counter);
// 模拟可能的异常退出
if (counter == 15) {
printf("进程 %s 模拟异常退出\n", name);
exit(1);
}
sleep(1);
}
}
// 父进程记录监控信息
if (monitored_count < MAX_MONITORED_PROCESSES) {
monitored_processes[monitored_count].pid = pid;
strncpy(monitored_processes[monitored_count].name, name,
sizeof(monitored_processes[monitored_count].name) - 1);
monitored_processes[monitored_count].start_time = time(NULL);
monitored_processes[monitored_count].monitoring = 1;
monitored_processes[monitored_count].stop_signal_sent = 0;
monitored_count++;
}
return pid;
}
// 显示监控状态
void show_monitoring_status() {
printf("\n=== 进程监控状态 ===\n");
time_t current_time = time(NULL);
printf("%-8s %-20s %-12s %-12s %-10s\n",
"PID", "名称", "运行时间", "监控状态", "停止信号");
printf("%-8s %-20s %-12s %-12s %-10s\n",
"---", "----", "--------", "--------", "--------");
for (int i = 0; i < monitored_count; i++) {
const monitored_process_t* proc = &monitored_processes[i];
int runtime = current_time - proc->start_time;
char runtime_str[16];
char monitor_str[16];
char signal_str[16];
snprintf(runtime_str, sizeof(runtime_str), "%ds", runtime);
snprintf(monitor_str, sizeof(monitor_str),
proc->monitoring ? "监控中" : "已停止");
snprintf(signal_str, sizeof(signal_str),
proc->stop_signal_sent ? "已发送" : "未发送");
printf("%-8d %-20s %-12s %-12s %-10s\n",
proc->pid, proc->name, runtime_str,
monitor_str, signal_str);
}
printf("==================\n\n");
}
// 处理进程状态变化
void handle_process_status_change(const siginfo_t* info) {
printf("[%ld] 进程状态变化: PID=%d ", time(NULL), info->si_pid);
switch (info->si_code) {
case CLD_EXITED:
printf("正常退出,退出码=%d\n", info->si_status);
break;
case CLD_KILLED:
printf("被信号杀死,信号=%d(%s)\n",
info->si_status, strsignal(info->si_status));
break;
case CLD_DUMPED:
printf("被信号杀死并产生core dump,信号=%d(%s)\n",
info->si_status, strsignal(info->si_status));
break;
case CLD_STOPPED:
printf("被信号停止,信号=%d(%s)\n",
info->si_status, strsignal(info->si_status));
break;
case CLD_CONTINUED:
printf("继续执行\n");
break;
default:
printf("未知状态=%d\n", info->si_code);
break;
}
// 更新监控信息
for (int i = 0; i < monitored_count; i++) {
if (monitored_processes[i].pid == info->si_pid) {
if (info->si_code == CLD_EXITED ||
info->si_code == CLD_KILLED ||
info->si_code == CLD_DUMPED) {
monitored_processes[i].monitoring = 0;
}
break;
}
}
}
// 监控循环
int monitoring_loop() {
printf("开始进程监控循环...\n");
printf("按 Ctrl+C 停止监控\n\n");
siginfo_t info;
int active_processes = monitored_count;
while (!stop_monitoring && active_processes > 0) {
// 非阻塞等待进程状态变化
if (waitid(P_ALL, 0, &info, WEXITED | WSTOPPED | WCONTINUED | WNOHANG) == -1) {
if (errno == ECHILD) {
printf("没有子进程可监控\n");
break;
} else if (errno == EINTR) {
printf("监控被信号中断\n");
continue;
} else {
perror("waitid监控失败");
break;
}
}
// 处理状态变化
if (info.si_pid != 0) {
handle_process_status_change(&info);
active_processes--;
show_monitoring_status();
} else {
// 没有状态变化,定期显示状态
static int status_counter = 0;
status_counter++;
if (status_counter % 10 == 0) { // 每10秒显示一次
show_monitoring_status();
}
sleep(1);
}
}
return 0;
}
// 优雅停止所有进程
void graceful_stop_all_processes() {
printf("优雅停止所有监控的进程:\n");
time_t start_time = time(NULL);
// 发送停止信号给所有活跃进程
for (int i = 0; i < monitored_count; i++) {
if (monitored_processes[i].monitoring &&
!monitored_processes[i].stop_signal_sent) {
printf("发送SIGTERM给进程 %s (PID: %d)\n",
monitored_processes[i].name,
monitored_processes[i].pid);
kill(monitored_processes[i].pid, SIGTERM);
monitored_processes[i].stop_signal_sent = 1;
}
}
// 等待进程结束(最多10秒)
siginfo_t info;
int remaining_processes = 0;
do {
remaining_processes = 0;
// 检查还有多少进程在运行
for (int i = 0; i < monitored_count; i++) {
if (monitored_processes[i].monitoring) {
remaining_processes++;
}
}
if (remaining_processes > 0) {
printf("等待 %d 个进程结束...\n", remaining_processes);
// 等待进程结束
if (waitid(P_ALL, 0, &info, WEXITED | WNOHANG) == 0) {
if (info.si_pid != 0) {
handle_process_status_change(&info);
remaining_processes--;
}
}
// 检查超时
if (time(NULL) - start_time > 10) {
printf("超时,强制终止剩余进程\n");
for (int i = 0; i < monitored_count; i++) {
if (monitored_processes[i].monitoring) {
printf("发送SIGKILL给进程 %s (PID: %d)\n",
monitored_processes[i].name,
monitored_processes[i].pid);
kill(monitored_processes[i].pid, SIGKILL);
}
}
break;
}
sleep(1);
}
} while (remaining_processes > 0);
printf("所有进程已停止\n");
}
int main() {
printf("=== 信号处理与进程监控示例 ===\n");
// 设置信号处理
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
// 创建被监控的进程
printf("1. 创建被监控的进程:\n");
pid_t proc1 = create_long_running_process("Worker1");
pid_t proc2 = create_long_running_process("Worker2");
pid_t proc3 = create_long_running_process("Worker3");
if (proc1 == -1 || proc2 == -1 || proc3 == -1) {
fprintf(stderr, "创建监控进程失败\n");
exit(EXIT_FAILURE);
}
printf("创建了 %d 个监控进程\n", monitored_count);
show_monitoring_status();
// 演示不同类型的等待选项
printf("2. 演示不同等待选项:\n");
// 创建测试进程用于演示
pid_t test_proc = fork();
if (test_proc == 0) {
printf("测试进程启动\n");
sleep(3);
printf("测试进程正常退出\n");
exit(0);
}
if (test_proc != -1) {
printf("创建测试进程 PID: %d\n", test_proc);
// 等待特定进程正常退出
siginfo_t info;
printf("等待进程 %d 正常退出...\n", test_proc);
if (waitid(P_PID, test_proc, &info, WEXITED) == 0) {
printf("进程 %d 正常退出,退出码: %d\n",
info.si_pid, info.si_status);
}
}
// 启动监控循环
printf("\n3. 启动进程监控循环:\n");
monitoring_loop();
// 优雅停止所有进程
printf("\n4. 优雅停止所有进程:\n");
graceful_stop_all_processes();
show_monitoring_status();
// 演示资源清理
printf("\n5. 资源清理演示:\n");
// 确保没有僵尸进程
siginfo_t cleanup_info;
int cleanup_count = 0;
while (waitid(P_ALL, 0, &cleanup_info, WEXITED | WNOHANG) == 0 &&
cleanup_info.si_pid != 0) {
printf("清理僵尸进程: PID %d\n", cleanup_info.si_pid);
cleanup_count++;
}
if (cleanup_count > 0) {
printf("共清理 %d 个僵尸进程\n", cleanup_count);
} else {
printf("没有需要清理的僵尸进程\n");
}
printf("\n=== 信号处理与进程监控演示完成 ===\n");
return 0;
}
编译和运行 链接到标题
# 编译示例1
gcc -o waitid_example1 waitid_example1.c
./waitid_example1
# 编译示例2
gcc -o waitid_example2 waitid_example2.c
./waitid_example2
# 编译示例3
gcc -o waitid_example3 waitid_example3.c
./waitid_example3
# 编译示例4
gcc -o waitid_example4 waitid_example4.c
./waitid_example4
重要注意事项 链接到标题
- siginfo_t结构: 提供比传统wait函数更详细的状态信息
- 非阻塞选项: WNOHANG允许非阻塞等待
- 多次等待: WNOWAIT允许不回收进程,可多次等待
- 状态监控: 支持监控进程的暂停、继续等状态
- 进程组支持: 可以等待整个进程组
- 错误处理: 必须检查返回值并处理EINTR等错误
- 资源管理: 及时清理僵尸进程
最佳实践 链接到标题
- 使用siginfo_t: 充分利用详细的状态信息
- 非阻塞等待: 在需要响应其他事件时使用WNOHANG
- 信号处理: 正确处理EINTR错误
- 进程组管理: 合理使用P_PGID管理进程组
- 优雅停止: 实现进程的优雅停止机制
- 资源清理: 确保及时清理僵尸进程
- 错误日志: 记录进程状态变化的详细信息
通过这些示例,你可以理解waitid在进程管理方面的强大功能,它为Linux系统提供了灵活、精确的进程控制能力,特别适用于复杂的多进程应用程序。