Bash线程:等待所有工作线程完成不起作用?

时间:2010-02-14 01:57:05

标签: bash multithreading

我正在编写一个小脚本,它将在主线程中创建存档,每个存档完成后,将通过调用函数创建一个新线程,该函数将负责上传这些存档。我希望在后台完成上传的原因是,在上传以前的档案时可以创建另一个档案。

我遇到的问题是在脚本的最后。也就是说,主线程不会等待所有上传线程在退出之前完成。查看以下简化脚本(我删除/更改了与问题无关的代码部分)

function func {
for files in /home/somewhere/
  do
    echo "Uploading $1" &
  done
wait
}

find /home/some/path -type f | while read filename ; do
  echo "Creating archive of $filename"
  func $somevariable &
done

wait

在创建最后一个存档之前,所有内容都执行得非常好,然后脚本在所有func个线程完成之前结束,而许多文件都没有上传。

感谢您的想法。

5 个答案:

答案 0 :(得分:12)

更新:评论中的好点。

所以,再看看,问题是管道创建的子shell到循环。这是构建脚本的一种好方法,但你需要在shell中进行最终等待,从而分离后台任务。

所以做这样的事情:

find /home/some/path -type f | (while read filename; do
    echo "Creating archive of $filename"
    func $somevariable &
  done
  wait
)

答案 1 :(得分:6)

棘手!问题是这个块

find /home/some/path -type f | while read filename ; do
  ...
done

创建子shell。 func $ somevariable作业在子shell中创建。父shell看到创建的所有后台作业 it 已完成,它不会跟踪由它生成的子shell创建的后台作业。

最简单的解决方法是从父shell创建后台作业。您可以通过不使用管道来避免创建子shell:

while read filename ; do
  ...
done < <(find /home/some/path -type f)

那么,这会为find创建一个子shell--但是while块不再是子shell。

请注意,上述内容仅适用于bash。 (不知道ksh或zsh,也许它也适用于那里。但它不会在灰和其他sh衍生物下起作用。)

答案 2 :(得分:3)

如果执行wait没有参数,则应该等待当前活动的子进程完成。

问题可能是“所有当前活跃的子进程”并不意味着您认为在这种情况下它意味着什么。特别是,如果您在子shell中创建管道,那么它们是否会在父shell中等待它们并不完全清楚。

我怀疑wait实际上只等待jobs输出中显示的进程/管道。尝试一些实验......

可能的替代方法是捕获子进程ID并对每个id进行wait n调用。

答案 3 :(得分:-1)

您可以循环,直到jobs命令返回任何内容作为替代方法。

答案 4 :(得分:-1)

您可以尝试使用此脚本。正是这样做的。 https://github.com/pabloniklas/BASH/blob/master/lib_cpu.sh