繁体   English   中英

后台和挂起的流程-在C中实现作业控制Shell

[英]Background and suspended processes - Implementing a Job Control Shell in C

我正在Linux中以C语言实现作业控制外壳,作为与操作系统相关的主题的项目。 我有一个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发送给父进程,以告知有关此信息。 然后,我有一个信号处理程序,如此处所示,对于该作业状态链表的每个节点,检查该节点中表示的进程是否已经退出,如果已经退出,则将该节点从链表中删除。 以下是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在垃圾上分支。 在假设status有意义之前,您需要检查waitpid的实际返回值。

最重要的其他问题是:

  • 允许内核仅发送一个SIGCHLD来告诉您已经退出了多个进程。 当您收到SIGCHLD ,您需要循环调用waitpid(0, &status, WNOHANG) ,直到它告诉您不再有等待的进程,并且您需要处理(没有双关语) 所有退出的进程ID它告诉你有关。

  • 调用printf或从异步信号处理程序中free是不安全的。 而是将终止的进程添加到延迟任务列表中。 确保在使用该列表的主循环代码中阻止SIGCHLD。

  • 不要自己在处理程序中阻塞和解除阻塞SIGCHLD 具有不可避免的比赛条件。 相反,让内核通过正确设置信号处理程序为您完成原子操作:使用sigaction ,不要将SA_NODEFER放在sa_flags (除非您有充分的理由不这样做,请务必SA_RESTART放入sa_flags中。)

  • 文字数字17应该是信号常数SIGCHLD 在整个历史上, 某些信号在整个Unix上一直稳定,但是SIGCHLD并不是其中之一。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM