2012-11-02 40 views
13

http://bugs.python.org/msg160297 Lesen, kann ich ein einfaches Skript geschrieben von Stephen White sehen, die zeigt, wie Bugs Python threading mit dieser Ausnahme bisVerstehe Python threading Fehler

Exception AttributeError: AttributeError("'_DummyThread' object has no attribute '_Thread__block'",) in <module 'threading' 

Da Stephen White Quellcode (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) 

wie würden wir es neu schreiben, so dass dieser Fehler behoben ist?

+0

Es scheint mir, dass Sie alles als 'time.sleep (3)' schreiben könnten. Ich denke, Sie sollten angeben, was die neu geschriebenen Programme tatsächlich tun sollten. –

+3

@JanneKarila Das Programm demonstriert lediglich einen Python-Fehler, den Sie sehen, wenn Sie ihn in Python 2.7 ausführen. Die Anforderung besteht darin, den Fehler zu umgehen, ohne auf eine Python-Version zu aktualisieren, die ihn behebt. – user4815162342

Antwort

33

The bug tritt wegen einer schlechten Wechselwirkung zwischen Dummy-Thread-Objekte durch die threading API erstellt, wenn ein threading.currentThread() auf einem fremden Thread ruft, und die threading._after_fork Funktion, die so genannte Ressourcen nach einem Aufruf von os.fork() aufzuräumen.

um den Fehler zu umgehen, ohne Quelle der Python zu modifizieren, Affe-Patch threading._DummyThread mit einer no-op Umsetzung __stop:

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

Die Ursache des Fehlers ist am besten in den Kommentaren von Richard Oudkerk und cooyeah verengt. Was passiert, ist die folgende:

  1. Das threading Modul ermöglicht threading.currentThread() von einem Thread nicht durch die threading API-Aufrufe erstellt aufgerufen werden. Es gibt dann eine "Dummy-Thread" -Instanz zurück, die eine sehr begrenzte Teilmenge der Thread-API unterstützt, aber immer noch nützlich ist, um den aktuellen Thread zu identifizieren.

  2. threading._DummyThread ist als Unterklasse von Thread implementiert. Thread Instanzen enthalten normalerweise einen internen Aufruf (self.__block), der den Verweis auf eine für die Instanz zugewiesene Sperre auf Betriebssystemebene enthält. Da die öffentlichen Thread Methoden, die möglicherweise mit self.__block enden, alle durch _DummyThread überschrieben werden, gibt der Konstruktor _DummyThread absichtlich die Sperre auf Betriebssystemebene durch Löschen von self.__block frei.

  3. threading._after_fork bricht die Verkapselung und ruft den privaten Thread.__stop Methode auf allen registrierten Themen, einschließlich der Dummy diejenigen, in denen __stop nie aufgerufen werden sollte. (Sie wurden nicht von Python gestartet, daher wird ihr Stoppen auch nicht von Python verwaltet.) Da die Dummy-Threads nichts über __stop wissen, erben sie es von Thread, und diese Implementierung greift glücklicherweise auf das private __block-Attribut zu existieren in _DummyThread Instanzen. Dieser Zugriff verursacht schließlich den Fehler.

Der Fehler wird in dem Zweig von 2,7 festgelegt, wenn modifying Thread.__stop not to break__block gelöscht. Der 3.x-Zweig, in dem __stop als _stop geschrieben und daher geschützt ist, behebt es durch overriding _DummyThread's _stop to do nothing.

+0

Ah ... Ich verstehe es jetzt ... Danke! –

+0

Hervorragende Erklärung! –