Cal*_*eng 15 python python-multithreading
阅读http://bugs.python.org/msg160297,我可以看到一个由Stephen White编写的简单脚本,它演示了python线程如何在这个异常中出错
Exception AttributeError: AttributeError("'_DummyThread' object has no attribute '_Thread__block'",) in <module 'threading'
Run Code Online (Sandbox Code Playgroud)
鉴于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)
Run Code Online (Sandbox Code Playgroud)
我们如何重新编写它以便解决此错误?
use*_*342 34
该错误的发生是因为threading当一个threading.currentThread()外部线程调用时由API 创建的虚拟线程对象与调用后调用的threading._after_fork函数调用之间的错误交互os.fork().
要在不修改Python源代码的情况下解决bug,threading._DummyThread使用no-op实现的monkey-patch __stop:
import threading
threading._DummyThread._Thread__stop = lambda x: 42
Run Code Online (Sandbox Code Playgroud)
Richard Oudkerk和cooyeah在评论中最好地缩小了这个错误的原因.会发生什么是以下情况:
该threading模块允许threading.currentThread()从不是由threadingAPI调用创建的线程调用.然后它返回一个"虚拟线程"实例,它支持非常有限的ThreadAPI 子集,但仍然可用于识别当前线程.
threading._DummyThread实现为.的子类Thread.Thread实例通常包含一个内部callable(self.__block),它继续引用为该实例分配的OS级锁.由于Thread可能最终使用的公共方法self.__block都被覆盖_DummyThread,因此_DummyThread构造函数通过删除有意释放操作系统级别的锁self.__block.
threading._after_fork打破封装并Thread.__stop在所有已注册的线程上调用私有方法,包括虚拟的,__stop从不打算调用.(它们不是由Python启动的,所以它们的停止也不是由Python管理的.)由于虚拟线程不知道__stop,它们从中继承Thread,并且该实现愉快地访问实例__block中不存在的私有属性_DummyThread.此访问最终导致错误.
通过在删除时修改Thread.__stop不中断来修复2.7分支中的错误__block.3.X分支,在那里__stop被拼成_stop,因此保护,以修复它覆盖_DummyThread的_stop什么也不做.