实现自定义ps命令:进程链表维护与后台进程管理问题求助
解决方案
一、解决后台进程时父进程阻塞的问题
- 替换阻塞的
wait(NULL)为非阻塞回收或信号驱动回收- 方法1:使用
waitpid(-1, NULL, WNOHANG)做非阻塞轮询。在每次处理用户命令(比如输入新命令、执行showProcs)之前,调用该函数批量回收已终止的子进程,不会阻塞父进程。// 示例:处理用户输入前回收僵尸进程 pid_t pid; while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) { deleteMe(pid); } - 方法2:注册
SIGCHLD信号处理函数,子进程终止时自动触发回收,无需轮询更高效。void sigchld_handler(int sig) { pid_t pid; // 循环回收所有已终止子进程,避免漏收 while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) { deleteMe(pid); } } // 程序初始化时注册信号 signal(SIGCHLD, sigchld_handler);
- 方法1:使用
二、修复deleteMe函数的误删问题
- 先验证进程状态,再执行删除
误删多因未正确判断进程是否存活就删除节点。用kill(pid, 0)检查进程状态:返回0表示进程存活,返回-1且errno为ESRCH表示进程已终止。
执行void deleteMe(pid_t target_pid) { struct proc_node *prev = NULL; struct proc_node *curr = head; while (curr != NULL) { if (curr->pid == target_pid) { // 验证进程是否已终止 if (kill(target_pid, 0) == -1 && errno == ESRCH) { // 执行链表节点删除 if (prev == NULL) { head = curr->next; } else { prev->next = curr->next; } free(curr); break; } else { // 进程仍在运行,跳过 prev = curr; curr = curr->next; } } else { prev = curr; curr = curr->next; } } }showProcs时,也要遍历链表并检查每个节点的进程状态,只输出kill(pid, 0) == 0的进程。
三、后台进程机制补充
如果要支持类似Linux的后台命令(命令后加&),解析用户命令时判断是否有&后缀:
- 有
&时,创建子进程后不阻塞等待,直接将进程信息加入链表。 - 无
&时,用waitpid(child_pid, NULL, 0)等待子进程终止,之后从链表删除该进程。
内容的提问来源于stack exchange,提问作者mrOser5
相关产品推荐
相关产品推荐

