Bash`wait`命令,等待超过1个PID完成执行

时间:2016-11-02 10:28:01

标签: linux bash wait pid

我最近发布了一个问题,询问是否可以prevent PID's from being re-used

到目前为止答案似乎是否定的。 (没关系。)

但是,用户Diego Torres Milano添加了该问题的答案,我的问题就是答案。

迭戈回答说,

  

如果您害怕重复使用PID,那么等待时就不会发生这种情况   其他答案解释,你可以使用

echo 4194303 > /proc/sys/kernel/pid_max
     

减少你的恐惧; - )

我实际上并不理解迭戈为什么在这里使用了数字4194303,但这是另一个问题。

我的理解是我遇到了以下代码的问题:

for pid in "${PIDS[@]}"
do
    wait $pid
done

问题是我在一个数组中有多个PID,并且for循环将按顺序运行wait命令与数组中的每个PID,但我无法预测进程将以相同的顺序完成他们的PID存储在这个数组中。

即;以下可以发生:

  • 开始在数组索引0
  • 中等待PID
  • 在数组索引1中使用PID的进程终止
  • 新作业在系统上运行,导致PID存储在PID阵列的索引1中重用于另一个进程
  • wait终止,因为数组索引0中的PID退出
  • 开始在数组索引0 中等待PID,除了现在这是一个不同的过程,我们不知道它是什么
  • 重新使用wait当前正在等待永远不会的PID的运行过程终止。也许它是邮件服务器的PID或系统管理员已启动的东西。
  • wait一直等到找到下一个严重的linux bug并重新启动系统或停电
迭戈说:

  

如果你等待其他答案解释

,这将不会发生

即;我上面描述的情况不可能发生。

迭戈是否正确?

  • 如果是这样,为什么我上面描述的情况不会发生?

或者迭戈不正确吗?

  • 如果是这样,那么我今天晚些时候发布一个新问题......

附加说明

我发现这个问题可能会令人困惑,除非你知道PID是后台启动的PID过程。即;

my_function &
PID="$!"
PIDS+=($PID)

2 个答案:

答案 0 :(得分:22)

让我们来看看你的选择。

无条件等待所有后台工作

for i in 1 2 3 4 5; do
    cmd &
done
wait

这样做的好处很简单,但是你不能让机器忙碌。如果你想在旧工作完成后开始新工作,你就不能。在所有后台作业完成之前,您的机器得到的利用越来越少,此时您可以开始新的一批作业。

相关的是通过将多个参数传递给wait来等待作业子集的能力:

unrelated_job &
for i in 1 2 3 4 5; do
  cmd & pids+=($!)
done
wait "${pids[@]}"   # Does not wait for unrelated_job, though

以任意顺序等待单个作业

for i in 1 2 3 4 5; do
   cmd & pids+=($!)
done

for pid in "${pids[@]}"; do
   wait "$pid"
   # do something when a job completes
done

这样可以让你在工作完成后继续工作,但是 仍然存在其他而不是$pid的作业可能首先完成的问题,导致您的计算机未充分利用,直到$pid实际完成。但是,您仍然可以获得每个作业的退出状态,即使它在您实际等待之前完成也是如此。

等待 next 作业完成(bash 4.3或更高版本)

for i in 1 2 3 4 5; do
   cmd & pids+=($!)
done

for pid in "${pids[@]}"; do
   wait -n
   # do something when a job completes
done

在此,您可以等到 作业完成,这意味着您可以让您的计算机尽可能保持忙碌状态。唯一的问题是,您不一定知道完成了哪个作业,而没有使用jobs来获取有效流程列表并将其与pids进行比较。

其他选择?

shell本身并不是进行工作分配的理想平台,这就是为什么有大量程序用于管理批处理作业的原因:xargsparallelslurmqsub等等。

答案 1 :(得分:0)

这是旧的,但是由于pid冲突导致延迟wait等待一些随机无关的进程的情况尚未得到直接解决。

在内核级别是不可能的。它的工作方式是在父进程调用wait(2)¹之前,子进程仍然存在。因为孩子仍然存在,linux将耗尽pid而不是重用它。这有时会出现所谓的僵尸或“失效”过程 - 这些孩子已经退出但尚未被父母“收获”。

现在,在shell级别,您无需调用wait(1)¹即可获取子进程 - bash会自动执行此操作。我还没有确认,但是当你为很久以前退出的儿童pid运行wait $pid时,我会打赌bash意识到它已经收获了那个孩子并立即返回信息而不是等待任何事情。

¹wait(N)符号是用于消除API层之间歧义的约定 - N指的是命令/函数所在的手册部分。在这种情况下,我们有:

  • wait(2):系统调用 - 请参阅man 2 wait
  • wait(1):shell命令 - 请参阅man 1 waithelp wait

如果您想知道每个手册部分的内容,请尝试man N intro

相关问题