我在Linux上运行了一个Python3守护进程。这是一个正常的单线程进程,在后台运行,在主循环中执行task_name
,然后处理I / O.有时(一个月大约1或2次)它停止响应。当它发生时,我想调试问题。
我已经尝试了select.select()
,但是没有成功,因为守护进程的stdin / stdout被重定向到pyrasite
设备而pyrasite使用这个stdin / stdout,而不是它启动的控制台从
所以我添加了一个/dev/null
信号处理程序来记录堆栈跟踪。工作正常。
今天我冻结了。 SIGUSR1
显示,该守护进程位于" S" (可中断的睡眠)状态。排除了繁忙的循环。
服务器不响应ps
或SIGUSR
(用于关闭)。
我希望至少有一些暗示那里发生了什么。
在什么条件下,睡眠的Python3 Linux进程无法处理它应该处理的中断?
更新
我终于可以重现这个问题了。在添加了大量调试消息之后,我发现了一个竞争条件,我很快就会解决。
当守护程序没有响应时,它在SIGINT
处于休眠状态,其中os.read(p)
是新管道的读取端(请参阅:p
),其中没有人写入。
但是,我编写简单演示程序的所有尝试都失败了。当我尝试从空管读取时,程序按预期阻塞,但可能像往常一样被中断(使用SIGINT从其他终端终止)。这个谜团仍未解决。
UPDATE2:
最后一些代码!我故意选择低级系统调用。
os.pipe
如果你跑了这么多次,你就会得到这个:
import os
import time
import signal
import sys
def sighandler(*unused):
print("got signal", file=sys.stderr)
print("==========")
signal.signal(signal.SIGUSR1, sighandler)
pid = os.getpid()
rfd, wfd = os.pipe()
if os.fork():
os.close(wfd)
print("parent: read() start")
os.read(rfd, 4096)
print("parent: read() stop")
else:
os.close(rfd)
os.kill(pid, signal.SIGUSR1)
print("child: wait start")
time.sleep(3)
print("child: wait end")
这很好,但有时你会看到这个:
parent: read() start
got signal
child: wait start
child: wait end
parent: read() stop
这里发生了什么:
现在,由于程序中的错误,在步骤2中收到了信号,但未提供EOF,因此读取未完成,并且从未达到步骤6(信号处理)。
这是我能够提供的所有信息。