#include #include #include #include #include #include #include #define MAX_CHILDREN 1024 #define MAX_LINE 256 static pid_t child_pids[MAX_CHILDREN]; static int child_count = 0; static void sigchld_handler(int sig){ int saved_errno = errno; pid_t pid; int status; while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { printf("[SIGCHLD] 子进程 %d 已终止", pid); if (WIFEXITED(status)) printf(", 退出码=%d", WEXITSTATUS(status)); if (WIFSIGNALED(status)) printf(", 被信号 %d (%s) 终止", WTERMSIG(status), (WTERMSIG(status) == SIGTERM) ? "SIGTERM" : ""); printf("\n"); for (int i = 0; i < child_count; i++) { if (child_pids[i] == pid) { child_pids[i] = child_pids[child_count - 1]; child_count--; break; } } } errno = saved_errno; } static void child_main(void) { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_DFL; sigemptyset(&sa.sa_mask); sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGTERM); sigprocmask(SIG_BLOCK, &mask, NULL); printf("子进程 %d 启动\n", getpid()); /* 等待 SIGTERM 信号 */ int sig; sigwait(&mask, &sig); printf("killed by parent\n"); exit(100); } static void cmd_create(int n) { sigset_t block_mask, old_mask; sigemptyset(&block_mask); sigaddset(&block_mask, SIGCHLD); sigprocmask(SIG_BLOCK, &block_mask, &old_mask); int created = 0; for (int i = 0; i < n; i++) { if (child_count >= MAX_CHILDREN) { printf("子进程数已达上限 %d\n", MAX_CHILDREN); break; } pid_t pid = fork(); if (pid < 0) { perror("fork"); break; } if (pid == 0) { sigprocmask(SIG_SETMASK, &old_mask, NULL); child_main(); } child_pids[child_count++] = pid; created++; } sigprocmask(SIG_SETMASK, &old_mask, NULL); if (created > 0) { printf("已创建 %d 个子进程:", created); for (int i = child_count - created; i < child_count; i++) printf(" %d", child_pids[i]); printf("\n"); } } static void cmd_kill(int n, pid_t *pids) { for (int i = 0; i < n; i++) { int found = 0; for (int j = 0; j < child_count; j++) { if (child_pids[j] == pids[i]) { found = 1; break; } } if (!found) { printf("PID %d 不是当前管理的子进程, 跳过\n", pids[i]); continue; } if (kill(pids[i], SIGTERM) == 0) { printf("已向子进程 %d 发送终止信号\n", pids[i]); } else { perror("kill"); } } } static void cmd_ps(void) { sigset_t block_mask, old_mask; sigemptyset(&block_mask); sigaddset(&block_mask, SIGCHLD); sigprocmask(SIG_BLOCK, &block_mask, &old_mask); if (child_count == 0) { printf("当前无子进程\n"); } else { printf("当前子进程 (%d 个):", child_count); for (int i = 0; i < child_count; i++) printf(" %d", child_pids[i]); printf("\n"); } sigprocmask(SIG_SETMASK, &old_mask, NULL); } static void process_command(char *line) { size_t len = strlen(line); if (len > 0 && line[len - 1] == '\n') { line[len - 1] = '\0'; } if (len == 0) { return; } char *cmd = strtok(line, " "); if (!cmd) { return; } if (strcmp(cmd, "create") == 0) { char *arg = strtok(NULL, " "); if (!arg) { printf("用法: create \n"); return; } int n = atoi(arg); if (n <= 0) { printf("无效的子进程数量: %s\n", arg); return; } cmd_create(n); } else if (strcmp(cmd, "kill") == 0) { pid_t pids[256]; int n = 0; char *arg; while ((arg = strtok(NULL, " ")) && n < 256) { pids[n++] = atoi(arg); } if (n == 0) { printf("用法: kill ...\n"); return; } cmd_kill(n, pids); } else if (strcmp(cmd, "ps") == 0) { char *arg = strtok(NULL, " "); if (!arg || strcmp(arg, "-u") != 0) { printf("用法: ps -u\n"); return; } cmd_ps(); } else if (strcmp(cmd, "exit") == 0) { sigset_t block_mask, old_mask; sigemptyset(&block_mask); sigaddset(&block_mask, SIGCHLD); sigprocmask(SIG_BLOCK, &block_mask, &old_mask); int remaining = child_count; sigprocmask(SIG_SETMASK, &old_mask, NULL); if (remaining > 0) { printf("还有 %d 个子进程未终止, 请先 kill 或等待其结束\n", remaining); return; } printf("所有子进程已结束, 父进程退出\n"); exit(0); } else { printf("未知命令: %s\n", cmd); printf("支持: create | kill ... | ps -u | exit\n"); } } int main(void) { struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = sigchld_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART | SA_NOCLDSTOP; sigaction(SIGCHLD, &sa, NULL); /* 忽略 SIGTERM, 父进程不会被意外终止 */ signal(SIGTERM, SIG_IGN); printf("=== 子进程管理程序 ===\n"); printf("命令: create | kill ... | ps -u | exit\n"); char line[MAX_LINE]; while (1) { printf("> "); fflush(stdout); if (!fgets(line, sizeof(line), stdin)) { break; /* EOF */ } process_command(line); } printf("父进程退出\n"); return 0; }