同时执行的 Bash 脚本不会终止后台进程

同时执行的 Bash 脚本不会终止后台进程

我有许多与以下非常相似的 shell 脚本这个问题。每个脚本都会启动一些后台任务,用 记住它们的 PID $!,进行一些测试,然后终止后台进程。

我的问题是我想运行大量此类脚本。如果我手动逐个运行它们,它们可以正常工作:ps -a显示后台进程已被正确终止。

$ ./test_1.sh
$ ./test_2.sh

但是,如果我像这样在一个命令中运行它们:

$ ./test_1.sh; ./test_2.sh

由 启动的后台进程test_1.sh在 启动时未能终止test_2.sh。这会导致需要绑定的端口被占用test_2.sh。因此,即使test_1.sh发出了正确的kill命令,test_2.sh如果 紧接着 执行,也会崩溃test_1.sh

如果我在脚本之间插入延迟,则不会出现问题:

$ ./test_1.sh; sleep 1; ./test_2.sh

kill因此,据推测,在发出信号和进程实际终止并释放端口之间存在延迟。

我的问题是:

  1. 发生了什么事?这个平台有特殊要求吗?我使用的是 Mac OS X。但对于最初在 Linux 上编写脚本的人来说,这似乎不是什么问题。
  2. 有没有更好的方法来确保后台进程已被终止,而无需使用sleep脚本?


为了完整性,其中一个测试脚本如下所示:

#!/bin/sh

echo "starting up server 1(parent)..."
$JAVA siena.StartServer -port 7000 &
server1=$!
sleep 2

echo "starting up server 2(the first child)..."
$JAVA siena.StartServer -port 2000 -master senp://:7000 > outputs/test.out2 &
server2=$!

echo "starting up server 3(the second child)..."
$JAVA siena.StartServer -port 3000 -master senp://:7000 > outputs/test.out2 &
server3=$!

sleep 5

kill $server1
kill $server2
kill $server3

答案1

您必须等待进程终止。通常,等待 SIGTERM 和 SIGKILL 之间是一个好主意。

在没有请求正常关闭之前就直接向进程发送 SIGKILL 指令,这被认为是不礼貌的行为(在我看来,这相当不专业)。这不仅会造成不一致,还会隐藏错误的关闭程序(程序无法在要求的时间内关闭)。

我会使用类似的东西:

# Launch your processes...
DEADLINE=1   #seconds to wait
kill $server1 $server2 $server3
sleep $DEADLINE 
if kill -KILL $server1 $server2 $server3
then 
  echo "Warning: at least one process had not finished in $DEADLINE seconds" >&2
  sleep 1   ## Wait for these just-killed processes to actually die and free their ports
fi 

另一种方法是从服务器本身内部找到一个空闲端口(不绑定端口并以某种方式在分配的端口外进行通信)。这将允许并行测试。您可以将端口号写入命令行中指定的文件(而不是端口,您将传递文件名),从而更改-port 7000为类似于-port auto -port-file test-port.txt然后等待此文件出现然后-master senp://:$(cat test-port.txt)

另一个想法是根据 的信息自动找出netstat -ntl所需端口是否空闲。然后,您可以选择等待或指定一组新的可用端口。在您看到端口空闲和实际绑定之间可能会发生竞争条件,特别是如果您的分配算法是确定性和可重复的(例如使用从 40000 开始的第一个可用端口)。让操作系统自己选择一个空闲端口要可靠得多。

相关内容