15

http://bugs.python.org/msg160297を読むと、この例外を除いてPythonスレッドがどのようにバグを起こすかを示すStephenWhiteによって書かれた簡単なスクリプトを見ることができます。

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、次のno-op実装を使用したmonkey-patch __stop

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

バグの原因は、 RichardOudkerkcooyeahによるコメントで最もよく絞り込まれています。何が起こるかは次のとおりです。

  1. threadingモジュールは、API呼び出しthreading.currentThread()によって作成されていないスレッドから呼び出すことができます。threading次に、APIの非常に限定されたサブセットをサポートする「ダミースレッド」インスタンスを返しますが、Threadそれでも現在のスレッドを識別するのに役立ちます。

  2. threading._DummyThreadのサブクラスとして実装されThreadます。インスタンスには通常、インスタンスに割り当てられたOSレベルのロックへの参照を保持Threadする内部呼び出し可能()が含まれています。self.__block最終的に使用される可能性のあるパブリックThreadメソッドself.__blockはすべて、によってオーバーライドされる_DummyThreadため、_DummyThreadのコンストラクターは、を削除することによってOSレベルのロックを意図的に解放しますself.__block

  3. threading._after_forkカプセル化を解除し、呼び出されることを意図されていなかっThread.__stopたダミースレッドを含むすべての登録済みスレッドでプライベートメソッドを呼び出します。__stop(Pythonによって開始されなかったため、停止もPythonによって管理されません。)ダミースレッドは__stop、を知らないため、から継承し、その実装は、インスタンスに存在しないThreadプライベート属性に喜んでアクセスします。 。このアクセスにより、最終的にエラーが発生します。__block_DummyThread

が削除されたときに壊れないように変更するThread.__stopことで、2.7ブランチのバグが修正されました。__block3.xブランチは、__stopと綴られ_stopているため保護されており、何もしないように'sをオーバーライド_DummyThread_stopすることで修正されます。

于 2012-11-02T10:37:36.720 に答える