2012-11-02 4 views
13

lettura http://bugs.python.org/msg160297, posso vedere un semplice script scritto da Stephen White che dimostra come pitone threading bugs su con questa eccezioneCapire bug pitone filettatura

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

Dato il codice sorgente di 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) 

come potremmo riscrivere in modo che questo errore è stato risolto?

+0

Mi sembra che tu possa riscrivere tutto come 'time.sleep (3)'. Penso che dovresti specificare cosa dovrebbero fare effettivamente i programmi riscritti. –

+3

@JanneKarila Il programma mostra semplicemente un bug Python, che vedrai se lo esegui in Python 2.7. La richiesta è di aggirare il bug senza eseguire l'aggiornamento a una versione di Python che lo corregge. – user4815162342

risposta

33

The bug si verifica a causa di una cattiva interazione tra oggetti thread fittizi creati dal threading API quando si chiama threading.currentThread() su un filo straniero, e la funzione threading._after_fork, chiamato a ripulire risorse dopo una chiamata a os.fork().

Per aggirare il bug senza modificare la fonte di Python, scimmia-patch threading._DummyThread con un'implementazione no-op di __stop:

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

La causa del bug è meglio ristretto nei commenti da Richard Oudkerk e cooyeah. Ciò che accade è il seguente:

  1. Il modulo threading permette threading.currentThread() di essere chiamato da un thread non creato dalle chiamate API threading. Quindi restituisce un'istanza "thread fittizio" che supporta un sottoinsieme molto limitato dell'API Thread, ma è comunque utile per identificare il thread corrente.

  2. threading._DummyThread è implementato come sottoclasse di Thread. Le istanze Thread normalmente contengono un callable interno (self.__block) che mantiene il riferimento a un blocco a livello di sistema operativo allocato per l'istanza. Poiché i metodi pubblici Thread che potrebbero finire con l'utilizzo di self.__block vengono tutti annullati dal costruttore _DummyThread, _DummyThread rilascia intenzionalmente il blocco a livello di sistema eliminando self.__block.

  3. threading._after_fork rompe l'incapsulamento e chiama il Thread.__stop metodo privato su tutte le discussioni registrate, comprese quelle fittizie, in cui __stop non ha mai inteso ad essere invocate. (Non sono stati avviati da Python, quindi il loro arresto non è gestito da Python.) Poiché i thread fittizi non sanno di __stop, lo ereditano da Thread e quell'implementazione accede felicemente all'attributo privato __block che non esistono nelle istanze _DummyThread. Questo accesso causa infine l'errore.

Il bug è stato risolto nel ramo 2.7 da modifying Thread.__stop not to break quando __block è soppresso. Il ramo 3.x, dove __stop viene digitato come _stop e quindi protetto, lo corregge tramite overriding _DummyThread's _stop to do nothing.

+0

Ah ... ho capito ora ... Grazie! –

+0

Superba spiegazione! –