2016-11-06 60 views
3

目前我正在制作一个shell,它对它所执行的前台进程工作正常。现在我必须实施后台流程和工作控制,并且我对我应该如何处理它感到困惑。我明白,如果我想在后台运行proccesses,我应该设置他们的pgid,而不是等待他们,但是我试图收获他们时碰壁了...如何为SIGCHLD制作一个信号处理程序,以便在shell中获得后台进程?

我有两个结构:job和处理

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,&状态,WNOHANG),因为在信号处理程序中,forground进程当前正在执行finsihes。

这是否意味着我必须在每一个工作的每一个进程中通过waitpid(),只要获得一个SIGCHLD,以便我只等待非fg进程?

我真的不需要代码,只是解释一个很好的方法来做到这一点。

+1

“因为关闭机会在信号处理程序中当前正在执行finsihes的forground进程“。那么如果前台进程结束了呢?处理它。它不会在后台列表中,因此您知道这不是后台进程。 – kaylum

+1

尽管如果一个进程在信号处理程序中终止,您可以使用'sigaction'来屏蔽它们,在isr之后您可以处理其他进程的信号处理程序 – Anjaneyulu

+0

对不起,延迟响应。但kaylum,如果在fork的父节点开始等待之前forground进程在sighandler中完成,那么会导致waitpid在fork之后永久挂起的forground进程? – ParadoxicalEnigma

回答

1

我知道这对你来说真的很晚,可能无法解决,但我正在研究一个shell,并在试图找出同样的问题时遇到了你的问题。

无论如何,这似乎是问题在于让主流程等待所有前台儿童,但这对处理中的waitpid呼叫很困难。我是如何做到的,而不是在主进程中使用wait()调用,我刚收获处理程序中的所有进程,并将它们从适当的列表中删除(我目前有一个所有前台进程的列表和所有后台进程的列表),以及然后在主过程中,我做的事:

while(foreground process list is not empty) 
    pause(); 

pause()调用只是把该进程进入睡眠状态,直到被信号唤醒,在这种情况下SIGCHLD总会唤醒过程,这样是可以再次检查有任何需要等待的前台进程仍在运行。希望这可以帮助别人!

编辑:刚才意识到这可能会导致竞争条件,如果孩子在您检查列表不是空的之前终止,并且在您致电pause()之前。简单的解决方法是仅使用nanosleep而不是暂停,它仍然会被信号打断,但是可以让您选择定期检查列表大小,这样可以避免竞争情况在这种情况下

+0

谢谢,我刚刚完成作业时有点晚。自从你付出了额外的努力之后,我会标记这一点。 – ParadoxicalEnigma

相关问题