设计思路
- 数据结构选择:
- 使用结构体来表示每组子进程的相关信息,包括子进程数量、任务优先级以及记录子进程ID的数组。
- 例如:
typedef struct {
int num_processes;
int priority;
pid_t *pids;
} ProcessGroup;
- 同步机制运用:
- 使用
waitpid
函数来等待子进程结束。父进程需要按照优先级顺序遍历ProcessGroup
数组,并依次等待每组子进程完成。
- 为了处理子进程的异常退出,使用
signal
函数注册信号处理函数,当子进程因信号异常终止时,信号处理函数可以记录相关信息,父进程在等待子进程结束时可以检查这些信息。
- 异常处理:
- 信号处理函数中,通过
waitpid
获取子进程的退出状态,判断是否是异常退出(例如通过WIFSIGNALED
宏)。如果是异常退出,记录相关信号信息。
代码实现
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <string.h>
typedef struct {
int num_processes;
int priority;
pid_t *pids;
} ProcessGroup;
void signal_handler(int signum) {
pid_t pid;
int status;
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
if (WIFSIGNALED(status)) {
printf("Child %d terminated by signal %d\n", pid, WTERMSIG(status));
}
}
}
int main() {
// 示例数据,两组子进程
ProcessGroup groups[] = {
{3, 2, NULL},
{2, 1, NULL}
};
int num_groups = sizeof(groups) / sizeof(groups[0]);
// 为每组子进程分配pid数组
for (int i = 0; i < num_groups; i++) {
groups[i].pids = (pid_t *)malloc(groups[i].num_processes * sizeof(pid_t));
}
// 注册信号处理函数
signal(SIGCHLD, signal_handler);
// 创建子进程
for (int i = 0; i < num_groups; i++) {
for (int j = 0; j < groups[i].num_processes; j++) {
pid_t pid = fork();
if (pid == 0) {
// 子进程任务模拟
printf("Child %d (group %d) with priority %d is running\n", getpid(), i, groups[i].priority);
sleep(1); // 模拟任务执行
exit(0);
} else if (pid > 0) {
groups[i].pids[j] = pid;
} else {
perror("fork");
exit(EXIT_FAILURE);
}
}
}
// 父进程按照优先级顺序等待子进程完成
for (int i = 0; i < num_groups; i++) {
for (int j = 0; j < groups[i].num_processes; j++) {
pid_t pid = groups[i].pids[j];
int status;
waitpid(pid, &status, 0);
if (WIFEXITED(status)) {
printf("Child %d (group %d) exited normally with status %d\n", pid, i, WEXITSTATUS(status));
}
}
free(groups[i].pids);
}
return 0;
}
代码说明
- 数据结构定义:
ProcessGroup
结构体用于存储每组子进程的数量、优先级和子进程ID数组。
- 信号处理函数:
signal_handler
函数用于处理子进程异常退出信号,通过waitpid
获取子进程退出状态并打印异常信息。
- 主函数:
- 初始化
ProcessGroup
数组并分配内存。
- 注册
SIGCHLD
信号处理函数。
- 创建子进程并存储其ID。
- 父进程按照优先级顺序等待每组子进程完成,并处理正常和异常退出情况。最后释放分配的内存。