我正在为大学写一个玩具外壳,我必须在它结束时更新后台进程的状态。所以我提出了使SIGCHLD
的处理程序这样做的想法,因为该信号是在进程结束时发送的。问题是,为了实现命令jobs
,我必须将状态从“运行”更新为“终止”,首先我必须在我专用的数组中找到特定的进程,并且有一种方法可以实现是通过pid搜索,因为数组存储在jobs
中显示的信息。每个条目都存储进程pid,状态(字符串)和命令本身。
现在的问题是:有没有办法获得在信号结束时调用信号的过程的pid?
现在这是我的处理程序函数的样子:
void handler(int sig){
int child_pid;
child_pid = wait(NULL);
//finds the process with a pid identical
//to child_pid in the list and updates its status
...
}
由于wait(NULL)
返回自调用之后结束的第一个进程的pid,因此仅在另一个后台进程结束时更新状态,因此更新了错误的进程状态。
我们没有从wait()
和waitpid()
functions中找到很多东西,除了他们等待一个过程结束,所以任何见解都可能有所帮助。
虽然在信号处理程序中使用wait不是一个好主意,但您可以执行以下操作来完成您要执行的操作。
void handler(int sig){
int child_pid;
int status;
child_pid = waitpid(-1, &status, WUNTRACED | WNOHANG);
if(child_pid > 0)
{
// your code
// make sure to deal with the cases of child_pid < 0 and child_pid == 0
}
}
你在做什么在技术上并没有错,但是,使用waitpid
会更好。当你使用waitpid(-1,...)
时,它的工作方式类似于你使用wait(...)
并且不仅会等待指定的进程,而且会终止任何进程。主要区别在于您可以指定WUNTRACED
,它将暂停执行,直到等待集中的进程终止或停止。 WNOHANG
将告诉waitpid
不要暂停执行该过程。您不希望暂停处理程序。
如果多个信号被发送到同一个进程,即由于多个子节点同时终止,那么似乎只发送了一个信号,因为信号处理程序不会再次执行。这是由于信号的发送方式;当一个信号被创建时,它被放入一个异常表中,然后进程“接收”它;信号不使用队列。为了解决这个问题,你需要迭代waitpid(-1,...)
调用,直到它返回0,以确保你收获所有被终止的孩子。
另外,请注意你收获孩子的其他地方(请注意,如果孩子已经被收获,那么如果使用waitpid
旗子,WNOHANG
将返回0)。我认为这是导致您看到的状态仅在另一个后台进程结束时更新的原因。例如,因为你正在制作一个玩具外壳,我假设你正在等待某个地方的前台进程,如果你在那里以及你的处理程序中使用wait函数,你可以得到两件事中的一件。孩子在'等待前台进程'方法中获得收益,然后当执行处理程序时,没有任何东西可以收获。 2,孩子在处理程序方法中获得收益,然后'等待前台进程'永远不会退出。