阅读http://bugs.python.org/msg160297,我可以看到一个由Stephen White编写的简单脚本,它演示了python线程如何在此异常中出错
Exception AttributeError: AttributeError("'_DummyThread' object has no attribute '_Thread__block'",) in <module 'threading'
鉴于Stephen White的源代码(http://bugs.python.org/file25511/bad-thread.py),
import os
import thread
import threading
import time
def t():
threading.currentThread() # Populate threading._active with a DummyThread
time.sleep(3)
thread.start_new_thread(t, ())
time.sleep(1)
pid = os.fork()
if pid == 0:
os._exit(0)
os.waitpid(pid, 0)
我们如何重新编写它以便解决此错误?
答案 0 :(得分:34)
The bug是因为在外部线程上调用threading
时由threading.currentThread()
API创建的虚拟线程对象与调用的threading._after_fork
函数之间的交互不良在致电os.fork()
后清理资源。
要在不修改Python源代码的情况下解决错误,使用threading._DummyThread
的无操作实现来修补__stop
:
import threading
threading._DummyThread._Thread__stop = lambda x: 42
Richard Oudkerk和cooyeah在评论中最好缩小错误原因。会发生以下情况:
threading
模块允许从非threading.currentThread()
API调用创建的线程调用threading
。然后它返回一个“虚拟线程”实例,该实例支持Thread
API的非常有限的子集,但仍然可用于识别当前线程。
threading._DummyThread
是作为Thread
的子类实现的。 Thread
个实例通常包含一个内部可调用(self.__block
),它可以引用为该实例分配的操作系统级锁。由于可能最终使用Thread
的公开self.__block
方法被_DummyThread
覆盖,_DummyThread
的构造函数通过删除self.__block
来故意释放操作系统级锁定
threading._after_fork
打破了封装,并在所有已注册的线程上调用私有Thread.__stop
方法,包括虚拟的线程,其中__stop
从未打算调用。 (它们不是由Python启动的,所以它们的停止也不是由Python管理的。)由于虚拟线程不知道__stop
,它们从Thread
继承它,并且该实现很愉快地访问__block
个实例中不存在的私有_DummyThread
属性。此访问最终会导致错误。
当删除__block
时,错误在modifying Thread.__stop
not to break的{2.7}分支中得到修复。 3.x分支,__stop
拼写为_stop
并因此受到保护,将其修复为overriding _DummyThread
's _stop
to do nothing。