我正在linux中用c实现一个作业控制shell,作为一个与操作系统相关主题的项目。我有一个main()函数,它负责子进程管理,有一个链接列表,如图所示,其中存储了后台和挂起的作业信息:typedef struct job_{ pid_t pgid; /* group id = process lider id */ char * command; /* program name */ enum job_state state; struct job_ *next; /* next job in the list */} job;每当一个子进程退出或停止时,都会向父进程发送一个通知。然后,我有一个信号处理程序,如图所示,对于该作业状态链表的每个节点,检查在该节点中表示的进程是否已退出,如果它退出,则从链表中删除该节点。以下是sigchld处理程序的代码,其中“job_list”是存储信息的链接列表:void mySIGCHLD_Handler(int signum) { block_SIGCHLD(); if (signum == 17) { job *current_node = job_list->next, *node_to_delete = NULL; int process_status, process_id_deleted; while (current_node) { /* Wait for a child process to finish. * - WNOHANG: return immediately if the process has not exited */ waitpid(current_node->pgid, &process_status, WNOHANG); if (WIFEXITED(process_status) != 0) { node_to_delete = current_node; current_node = current_node->next; process_id_deleted = node_to_delete->pgid; if (delete_job(job_list, node_to_delete)) { printf("Process #%d deleted from job list\n", process_id_deleted); } else { printf("Process #%d could not be deleted from job list\n", process_id_deleted); } } else { current_node = current_node->next; } } } unblock_SIGCHLD();}问题是,当调用处理程序时,有些条目不应该被删除,因为它们所代表的进程没有退出,当它们不应该被删除时,任何人都会知道为什么会出现这种情况。谢谢你,也为你失去的时间感到抱歉:( 最佳答案 我在这段代码中看到许多问题,但最直接的问题可能是: waitpid(current_node->pgid, &process_status, WNOHANG); if (WIFEXITED(process_status) != 0) {当waitpid(pid, &status, WNOHANG)返回,因为进程没有退出,它不会向status写任何东西,所以随后的if在垃圾上分支。在假设waitpid有意义之前,您需要检查status的实际返回值。最重要的其他问题是:内核只允许发送一个SIGCHLD,告诉您已经退出了几个进程。当你得到一个 >时,你需要在循环中调用SIGCHLD,直到它告诉你没有更多的进程等待,而且你需要处理它告诉你的所有退出的进程ID。从异步信号处理程序调用waitpid(0, &status, WNOHANG)或printf是不安全的。而是将终止的进程添加到延迟任务列表中。确保在使用该列表的主循环代码中阻止sigchld。不要在处理程序中阻塞和解除阻塞free自己;这是不可避免的竞争条件。相反,让内核通过正确设置信号处理程序来为您实现这一点:使用SIGCHLD并且不要将sigaction放入SA_NODEFER中。(除非你有充分的理由不这么做,否则一定要把sa_flags放进SA_RESTART。)文字数字17应该是信号常量sa_flags。在整个历史中,一些信号数在所有unix中都是稳定的,但是SIGCHLD不是其中之一。关于c - 后台和挂起的流程-在C中实现作业控制Shell,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50377402/
10-11 17:43