我对信号在进程组内传播的方式有疑问。这是我的情况和问题的解释:
我有一个应用程序,它是由 shell 脚本(带有 su)启动的。这个 shell 脚本本身是由一个使用 subprocess.Popen 的 python 应用程序启动的
我将 os.setpgrp 称为 preexec_function 并使用 ps 验证了 bash 脚本、su 命令和最终应用程序都具有相同的 pgid。
现在,当我向 bash 脚本(进程组的领导者)发送信号 USR1 时,应用程序有时会看到此信号,有时则不会。我不知道为什么我有这种随机行为(应用程序大约有 50% 的时间看到信号)
这是我正在测试的示例代码:
Python启动器:
#!/usr/bin/env python
p = subprocess.Popen( ["path/to/bash/script"], stdout=…, stderr=…, preexec_fn=os.setpgrp )
# loop to write stdout and stderr of the subprocesses to a file
# not that I use fcntl.fcntl(p.stdXXX.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
p.wait()
bash脚本:
#!/bin/bash
set -e
set -u
cd /usr/local/share/gios/exchange-manager
CONF=/etc/exchange-manager.conf
[ -f $CONF ] && . $CONF
su exchange-manager -p -c "ruby /path/to/ruby/app"
ruby 应用程序:
#!/usr/bin/env ruby
Signal.trap("USR1") do
puts "Received SIGUSR1"
exit
end
while true do
sleep 1
end
所以我尝试将信号发送到 bash 包装器(从终端或从 python 应用程序),有时 ruby 应用程序会看到信号,有时不会。我不认为这是一个日志记录问题,因为我试图用一种直接写入不同文件的方法来替换 puts。
你们知道什么可能是我的问题的根本原因以及如何解决它吗?
最佳答案
您的信号处理程序做得太多了。如果从信号处理程序中退出,则不确定缓冲区是否已正确刷新,换句话说,您可能无法正常退出程序。当程序已经在信号处理程序中时,要小心接收到的新信号。
尝试修改您的 Ruby 源代码以在设置“退出”标志后立即从主循环中退出程序,并且不要从信号处理程序本身退出。
您的 Ruby 应用程序变为:
#!/usr/bin/env ruby
$done = false
Signal.trap("USR1") do
$done = true
end
until $done do
sleep 1
end
puts "** graceful exit"
哪个应该更安全。
对于真正的程序,您可以考虑使用互斥锁来保护您的标志变量。
关于python - 进程组中的所有子进程并不总是看到信号,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16714297/