【问题标题】:Why print operation within signal handler may change deadlock situation?为什么信号处理程序中的打印操作可能会改变死锁情况?
【发布时间】:2012-06-02 09:43:39
【问题描述】:

我得到了如下简单的程序:

import threading
import time
import signal

WITH_DEADLOCK = 0

lock = threading.Lock()

def interruptHandler(signo, frame):
    print str(frame), 'received', signo
    lock.acquire()
    try:
        time.sleep(3)
    finally:
        if WITH_DEADLOCK:
            print str(frame), 'release'
        lock.release()

signal.signal(signal.SIGINT, interruptHandler)
for x in xrange(60):
    print time.strftime("%H:%M:%S"), 'main thread is working'
    time.sleep(1)

因此,如果您启动该程序,并且在 3 秒内按两次 Ctrl+C,则不会出现死锁。每次按 Ctrl + C 时,都会显示正确的行。 如果您更改 WITH_DEADLOCK=1 并按 Ctrl+C 两次(3 秒内),则程序将挂起。

有人可以解释为什么打印操作会产生如此大的差异吗?

(我的python版本是2.6.5)

【问题讨论】:

  • 我的猜测是打印操作会改变以处理新信号(没有释放锁)......
  • 至少缺少global lock
  • 查看被中断的帧,我注意到当它挂起时,信号正在中断另一个帧。此外,将锁更改为递归可以阻止挂起的发生。这些告诉我它正在挂起,因为第二个处理程序正在中断第一个处理程序,然后等待第一个处理程序持有的锁。死锁是因为第一个在等待第二个返回,第二个在等待第一个释放锁。当它不挂起时,被中断的帧总是一样的。至于为什么会这样,我还是不确定。
  • 我知道它挂在哪里,但我无法解释为什么它没有打印操作。将 Lock 更改为 RLock 将破坏评论部分的安全性(因为它是信号处理程序)
  • 令人惊讶的是,在 Python2 上没有print 并且确实没有it deadlocks even without print on Python3,它不会死锁。信号处理程序必须是可重入的(它甚至比线程安全更具限制性)。当执行第二个处理程序时,第一个处理程序被中断,因此它永远不会释放锁,第二个处理程序无法获得它 -> 死锁。

标签: python linux signals deadlock


【解决方案1】:

老实说,我认为 JF Sebastian 的评论是这里最合适的答案 - 你需要让你的信号处理程序可重入,而目前它不是,而且令人惊讶的是它在没有 print 语句的情况下仍然可以工作。

【讨论】:

  • 是的,J.F. Sebastian 的最后一条评论是我最喜欢的无论如何仍然没有答案为什么删除 print 操作不会挂起 python 2.x 中提供的代码。
猜你喜欢
  • 2012-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多