waitpid() 函数 returns ERROR (-1),为什么?

waitpid() function returns ERROR (-1), why?

我正在用 C 编写一个 Linux shell 类程序。

除其他外,我正在执行两个内置命令:jobs, history.jobs 中,我打印了当前工作命令的列表(在后台)。 在 history 中,我打印了到目前为止所有命令历史记录的列表,并为每个命令指定它是 运行 还是完成。

为了实现这两个,我的想法是有一个命令列表,将命令名称映射到它们的 PID。调用 jobs/history 命令后,我 运行 通过它们,检查哪些是 运行ning 或已完成,并相应地打印。

我在网上看到函数:waitpid(pid, &status, WNOHANG),可以在不停止进程的情况下从“PID”检测进程是否仍在 运行ning 或完成。 它运行良好,除了这个:

当程序处于活动状态时,函数 return 执行它。 当一个程序完成时,我第一次称它为 returns done,从那时起,如果使用相同的 PID 再次调用它,它会 returns -1 (ERROR).

例如,它看起来像这样:(& 表示后台命令)

$ sleep 3 &
$ jobs
sleep ALIVE 
$ jobs  (withing the 3 seconds)
sleep ALIVE
$ jobs (after 3 seconds)
sleep DONE
$ jobs 
sleep ERROR
$ jobs 
sleep ERROR
....

此外,这些不受我之前或之后可能执行的其他命令调用的影响,似乎上述行为独立于其他命令。

我在网上阅读了 waitpid 可能 return -1 的各种原因,但我无法确定我的情况的原因。此外,我尝试寻找如何理解 waitpid 错误的类型,但再次失败。

我的问题是:

  1. 您认为为什么会发生这种行为
  2. 如果您有解决方案(理想情况是它保持 returning DONE)
  3. 如果你对如何实现有更好的想法jobs/history命令被广泛接受

这个问题的一个解决方案是,一旦我得到“DONE”,我就将命令签署为 DONE,并且在打印它之前不再对其执行 waitid。这将解决问题,但我对为什么会发生这种情况一无所知

您应该熟悉在 Unix 环境中如何处理子进程。特别是阅读 Zombie processes.

当一个进程死亡时,它进入'zombie'状态,因此它的PID仍然被保留并唯一标识现在死亡的进程。僵尸进程上的成功 wait 会释放进程描述符及其 PID。因此,在同一 PID 上对 wait 的后续调用将失败,因为不再有具有该 PID 的进程(除非为新进程分配了相同的 PID,在这种情况下等待它是一个逻辑错误)。

您应该重构您的程序,以便如果 wait 成功并报告进程 DONE,您将该信息记录在您自己的数据结构中并且永远不会调用 wait再次在那个 PID 上。

为了比较,一旦一个进程完成,bourne shell 最后一次报告它,然后将其从作业列表中删除:

$ sleep 10 &
$ jobs
[1] + Running                 sleep 10
$ jobs
[1] + Running                 sleep 10
$ jobs
[1]   Done                    sleep 10
$ jobs
$