这是我在这里提交的第三个答案。这个函数处理信号中断,并在
SIGINT
收到。它使用
$BASHPID
exec
在游戏中使用的技巧
top answer
获取进程的PID(在本例中
$$
在一个
sh
调用)。它使用FIFO与负责杀戮和清理的子shell通信。(这就像我的烟斗
second answer
run_with_timeout ()
{
t=$1 ; shift
trap cleanup 2
F=$$.fifo ; rm -f $F ; mkfifo $F
# first, run main process in background
"$@" & pid=$!
# sleeper process to time out
( sh -c "echo \$\$ >$F ; exec sleep $t" ; echo timeout >$F ) &
read sleeper
# control shell. read from fifo.
# final input is "finished". after that
# we clean up. we can get a timeout or a
# signal first.
( exec 0
while : ; do
read input
case $input in
finished)
test $sleeper != 0 && kill $sleeper
rm -f $F
exit 0
;;
timeout)
test $pid != 0 && kill $pid
sleeper=0
;;
signal)
test $pid != 0 && kill $pid
;;
esac
done
) &
# wait for process to end
wait $pid
status=$?
echo finished >$F
return $status
}
cleanup ()
{
echo signal >$$.fifo
}
我尽量避免比赛条件。但是,我无法删除的一个错误源是进程在接近超时的同时结束。例如,
run_with_timeout 2 sleep 2
run_with_timeout 0 sleep 0
. 对我来说,后者给出了一个错误:
timeout.sh: line 250: kill: (23248) - No such process
因为它试图杀死一个已经退出的进程。