等待bash-builtin以100%的速度消耗CPU


16

至少在GNU bash版本4.3.42 x86_64和GNU bash版本4.3.11 x86_64上发生

我用sleep & wait $!一个简单的方法而不是简单的方法sleep来获得sleep信号的可中断性(如SIGUSR1)。但是wait当您运行以下命令时,bash-builtin的行为似乎很奇怪。

1号航站楼:

cat <(
   trap 'echo SIGUSR1' SIGUSR1;
   echo $BASHPID;
   while :;do
       sleep 1 &
       wait $!;
       echo test;
   done
   )&

2号航站楼:

kill -10 /the pid of the subshell, printed by the previous command/

1号航站楼:

^C (ctrl + C)

然后,我得到了以100%消耗CPU的子外壳。

1号航站楼:

pkill -P $(pgrep -P $$)

您是否知道为什么会发生这种行为?

注意cat <(/subshell/)不在后台时,不会发生任何问题。


体验这种行为的另一种方式

1号航站楼:

(
   trap 'echo SIGUSR1' SIGUSR1;
   echo $BASHPID;
   while :;do
       sleep 1 &
       wait $!;
       echo test;
   done
)&

2号航站楼:

kill -10 /the pid of the subshell, printed by the previous command/

1号航站楼:

fg
^C (ctrl + C)

然后,获取冷冻的贝壳。


体验这种行为的第三种方式

1号航站楼:

(
   trap 'echo SIGUSR1' SIGUSR1;
   echo $BASHPID;
   while :;do
       sleep 1 &
       wait $!;
       echo test;
   done
)

2号航站楼:

kill -10 /the pid of the subshell, printed by the previous command/

1号航站楼:

^C (ctrl + C)

然后,获取冷冻的贝壳。


要调试它,您可能必须从源代码构建Bash,并找出它在哪里循环(用调试器破坏它或添加打印语句)以及为什么循环。
哈兹

1
奇怪?我在这里无法重现此内容,我正在使用bash 4.3.42(1)-release(x86_64-pc-linux-gnu)。Debian 8.内核4.6.1-1。我完成了您说的所有测试,但CPU仍在正常运行...我所做的工作与您所说的完全相同,包括fg,然后按CTRL + C。
Luciano Andress Martini

我记得读过一些内容,这些内容与bash4.4中的内置和信号更改有关,也许这可能会受到影响。
phk

Bash 4.4.20修复了一个wait看起来与此类似的自旋循环问题。我被循环中永远产生的子流程所打动。但是,我在4.4.20上测试了您的方案,但这仍然是一个问题。有趣的是,当我在构建的版本上附加调试器时,我可以看到它正在循环运行,但是它具有中断它的作用,并且该循环将再次开始输出“测试”。换句话说:附加调试器使其停止自旋循环。
Halfgaar

Answers:


1

观察结果

  • ctrl+c发送SIGINT到1号航站楼的fg-process
  • 因此,kill -2 <PID>在终端2中执行与ctrl+c在终端1中执行相同
  • 在终端2中执行之前执行上述两个操作kill -10 <PID>之一可以SIGINT正确处理
  • 这样做后,执行kill -10 <PID>2号航站楼(发送信号SIGUSR1)不处理SIGINT正确,导致有问题的行为
  • 用()或()代替kill -2 <PID>端子2(SIGINT)总是可以正确处理信号。kill -15 <PID>SIGTERMkill -9 <PID>SIGKILL
  • kill -10 <PID>在终端2中执行会中断wait内置函数,但不会离开循环,因为testSIGUSR1捕获信号并继续循环之后会立即打印输出。
  • 发送SIGINT会中断执行循环并冻结外壳,或者它永不中断wait并保持等待/冻结状态。

结论

SIGINT无法正确处理和处理,或者在手动陷阱SIGUSR1或任何其他用户定义的陷阱后将其忽略。这意味着该进程仍然存在,这就是它吞噬/加热CPU或冻结外壳的原因。从终端2 执行kill -15 <PID>kill -9 <PID>终止该过程,会终止该过程,使您对终端1的控制权得到恢复,并放松了CPU。

为什么会出现此问题,仍然是一个谜,但我希望有人能确切解释幕后真正发生的事情。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.