2012-11-02 12 views
13

Czytanie http://bugs.python.org/msg160297 widzę prosty skrypt napisany przez Stephen White, który pokazuje, w jaki sposób błędy pyton gwintowania się z tym wyjątkiemZrozum pyton wątków błąd

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

Biorąc kod źródłowy Stephena White'a (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) 

jak chcielibyśmy ponownie napisać to tak, że błąd ten został rozwiązany?

+0

Wydaje mi się, że możesz przepisać to wszystko jako 'time.sleep (3)'. Sądzę, że powinieneś sprecyzować, co powinny teraz zrobić nowe programy. –

+3

@JanneKarila Program demonstruje tylko błąd w Pythonie, który zobaczysz, jeśli uruchomisz go w Pythonie 2.7. Wniosek dotyczy obejścia błędu bez aktualizacji do wersji Pythona, która ją naprawia. – user4815162342

Odpowiedz

33

The bug występuje z powodu złego współdziałania atrapy przedmiotów gwintów utworzonych przez threading API gdy jeden nazywa threading.currentThread() na wątku zagranicznego, a funkcja threading._after_fork, zwany oczyścić zasoby po wywołaniu os.fork().

celu obejścia błędu bez modyfikowania źródła Pythona, małpa-plaster threading._DummyThread z realizacją no-op __stop:

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

Przyczyną błędu jest najlepszy zawężony w komentarzach przez Richard Oudkerk i cooyeah. Co się dzieje, jest następujący:

  1. Moduł threading pozwala threading.currentThread() być wywoływana z wątku nie stworzonej przez threading API. Następnie zwraca instancję "dummy thread", która obsługuje bardzo ograniczony podzbiór interfejsu API Thread, ale nadal jest przydatna do identyfikowania bieżącego wątku.

  2. threading._DummyThread jest zaimplementowana jako podklasa Thread. Thread instancje zwykle zawierają wewnętrzną wywoływalną (self.__block), która zachowuje odwołanie do blokady poziomu systemu operacyjnego przydzielonej dla instancji. Ponieważ publiczne metody Thread, które mogą zakończyć używanie self.__block są nadpisywane przez konstruktor _DummyThread, _DummyThread, celowo zwalniają blokadę na poziomie systemu operacyjnego OS poprzez usunięcie self.__block.

  3. threading._after_fork przerywa hermetyzacji i wywołuje prywatną Thread.__stop metodę na wszystkie zarejestrowane wątków, w tym te atrapy, gdzie __stop nigdy nie miał się powoływać. (Nie zostały one uruchomione przez Python), więc ich zatrzymanie nie jest zarządzane przez Python). Ponieważ wątkowe wątki nie wiedzą o __stop, dziedziczą je od Thread, a ta implementacja z łatwością uzyskuje dostęp do prywatnego atrybutu __block, który nie istnieją w instancjach _DummyThread. Ten dostęp w końcu powoduje błąd.

Błąd został rozwiązany w 2,7 oddziału przez modifying Thread.__stop not to break gdy __block zostanie usunięty. Oddział 3.x, w którym __stop jest pisany jako _stop i dlatego jest chroniony, naprawia go przez overriding _DummyThread's _stop to do nothing.

+0

Ah ... teraz rozumiem ... Dzięki! –

+0

Wyjątkowe wyjaśnienie! –