如何为SIGCHLD制作一个信号处理器,它将在shell中获取后台进程?

如何为SIGCHLD制作一个信号处理器,它将在shell中获取后台进程?,c,linux,shell,process,C,Linux,Shell,Process,目前我正在制作一个shell,它可以很好地用于它执行的前台进程。现在我必须实施后台流程和工作控制,我真的很困惑我应该如何处理它。我明白,如果我想在后台运行进程,我应该设置它们的pgid,而不是等待它们,但是我在尝试收获它们时遇到了困难 我有两个结构:作业和过程 typedef struct job { int is_background_job; pid_t pgid; int job_status; process *p; // List of

目前我正在制作一个shell,它可以很好地用于它执行的前台进程。现在我必须实施后台流程和工作控制,我真的很困惑我应该如何处理它。我明白,如果我想在后台运行进程,我应该设置它们的pgid,而不是等待它们,但是我在尝试收获它们时遇到了困难

我有两个结构:作业和过程

typedef struct job {
    int is_background_job;
    pid_t pgid;
    int job_status;
    process *p;         // List of processes to execute for this job
    struct job *next;   // If a background job, it will be in a global linked list of job structs 
} job;

typedef struct process {
    char **argv;
    process *next;      // The next process to pipe to
} process;
重要的一点是,作业由流程结构的链表组成,并且有一个全局作业结构列表,它表示正在进行的所有后台作业

shell算法是一种标准算法

外壳:

get cmd from terminal
parse cmd and create a job struct filled with processes
if job is a background job:
  add it to global background job list
fork(), setpgid, and do the piping in a while loop of the job's processes   
if job is a foreground process:
  wait on the forked processes
else:
  don't wait // since it's a background process
continue to loop and read next cmd from terminal

现在是我的问题。如果我有一堆在后台执行的进程,这意味着它们中的任何一个(来自任何一个后台作业)都可以简单地结束,然后发送SIGCHLD。令人恼火的是,如果某个作业的所有进程都结束了,我必须将该作业从全局作业列表中删除。我不认为我可以在我的SIGCHLD处理程序中调用waitpid(-1,&status,WNOHANG)循环,因为放弃的进程在信号处理程序中执行finsihes的可能性很小

这是否意味着我必须在获得SIGCHLD后立即对每个作业的每个进程执行waitpid(),以便只在非fg进程上等待


我真的不需要代码,只需要一个好方法的解释。

我知道这已经很晚了,可能现在对你来说已经无关紧要了,但我也在开发一个shell,在试图解决同样的问题时遇到了你的问题

不管怎样,这里的问题似乎是让主进程等待所有前台子进程,但是在
SIGCHLD
处理程序中调用
waitpid
很难做到这一点。我是如何做到这一点的,而不是在主进程中使用
wait()
调用的,我只是获取了处理程序中的所有进程,并将它们从适当的列表中删除(我目前有一个所有前台进程的列表和所有后台进程的列表),然后在主进程中我做了:

while(foreground process list is not empty)
    pause();
pause()
调用只是将进程置于睡眠状态,直到它被信号唤醒,在这种情况下,
SIGCHLD
将始终唤醒进程,以便再次检查是否有任何前台进程仍在运行,需要等待。希望这对别人有帮助


编辑:刚刚意识到,如果在您检查列表是否为空之后,在您调用
pause()
之前,孩子立即终止,那么这可能会导致竞争条件。解决这个问题的简单方法是只使用
nanosleep
而不是暂停,它仍然会被一个信号中断,但给您定期检查列表大小的选项,这就避免了这种情况下的竞争条件

“因为前面的进程在信号处理程序中当前执行finsihes的可能性很小”。那么,如果前台进程完成了呢?处理好它。它不在后台列表中,因此您知道它不是后台进程。即使进程在信号处理程序中终止,您也可以使用
sigaction
屏蔽它们,并且在isr后,您可以处理其他进程信号处理程序抱歉响应太晚。但是kaylum,如果fork的父进程开始等待fork之前forgfround进程在sighandler中完成,那么这会导致fork之后forgfround进程的waitpid永远挂起吗?还有Anjanelyulu,如果子进程终止,我很好,因为信号处理程序将忽略SIGCHLD,直到它完成运行。我担心的是,如果forground进程完成并在signal sandler中收获,因为如果信号处理程序在“wait on forked process”(等待分叉进程)发生之前被调用(查看我上面的伪代码algo中的这条语句),那么就不会永远等待挂起了吗?谢谢,由于我刚刚完成了任务,现在已经有点晚了。因为你付出了额外的努力,所以我会记下这个。