15

阅读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)

我们将如何重写它以解决此错误?

4

1 回答 1

34

发生该错误的原因是在调用外部线程threading时由 API创建的虚拟线程对象与在调用.threading.currentThread()threading._after_forkos.fork()

要在不修改 Python 源代码的情况下解决该错误,请threading._DummyThread使用以下无操作实现的猴子补丁__stop

import threading
threading._DummyThread._Thread__stop = lambda x: 42

最好在Richard Oudkerkcooyeah的评论中缩小错误的原因。会发生以下情况:

  1. threading模块允许threading.currentThread()从不是由threadingAPI 调用创建的线程调用。然后它返回一个“虚拟线程”实例,该实例支持非常有限的ThreadAPI 子集,但对于识别当前线程仍然有用。

  2. threading._DummyThread被实现为 的子类ThreadThread实例通常包含一个内部可调用 ( self.__block),它保持对分配给实例的操作系统级锁的引用。Thread由于可能最终使用的公共方法self.__block都被 覆盖_DummyThread_DummyThread因此的构造函数有意通过删除来释放操作系统级别的锁self.__block

  3. threading._after_fork打破封装并Thread.__stop在所有注册线程上调用私有方法,包括虚拟线程,这些线程__stop从未打算被调用。(它们不是由 Python 启动的,因此它们的停止也不是由 Python 管理的。)由于虚拟线程不知道__stop,它们从 继承它Thread,并且该实现愉快地访问实例__block中不存在的私有属性_DummyThread. 这种访问最终导致错误。

在 2.7 分支中通过修改Thread.__stop__block删除时不中断修复了该错误。3.x 分支,__stop拼写为 as_stop并因此受到保护,通过覆盖_DummyThread's _stopto do nothing 来修复它。

于 2012-11-02T10:37:36.720 回答