2012-02-13 21 views
5

W wielowątkowym Pythonowego programu jeden wątek czasami prosi wejścia konsoli przy wbudowanej raw_input(). Chciałbym być w stanie zamknąć program przy znaku raw_input, wpisując^C w powłoce (tj. Z sygnałem SIGINT). Jednak gdy wątek potomny wykonuje raw_input, wpisanie^C nic nie robi - Przerwanie klawiatury nie jest wywoływane, dopóki nie uderzę return (pozostawiając raw_input).Przerwanie Pythona raw_input() w wątku dziecko z^C/KeyboardInterrupt

Na przykład, w następującym programie:

import threading 

class T(threading.Thread): 
    def run(self): 
     x = raw_input() 
     print x 

if __name__ == '__main__': 
    t = T() 
    t.start() 
    t.join() 

Wpisanie^C nie robi nic, aż po wejście jest zakończona. Jednakże, jeśli po prostu zadzwonimy pod numer T().run() (tj. W przypadku pojedynczego wątku: po prostu uruchom raw_input w głównym wątku),^C natychmiast zamknie program.

Można przypuszczać, że to dlatego, że SIGINT wysyłany jest do głównego wątku, który jest zawieszony (czekając na GIL), podczas gdy rozwidlone bloki gwintowania na konsoli czytać. Główny wątek nie wykonuje swojej procedury obsługi sygnału, dopóki nie pobierze GIL po zwróceniu wartości raw_input. (Proszę mnie poprawić, jeśli się mylę - nie jestem ekspertem od implementacji wątków Pythona.)

Czy istnieje sposób odczytu ze standardowego wejścia w sposób raw_input-like, pozwalając na obsługę SIGINT przez główną nić, a tym samym obniżyć cały proces?

[Mam obserwowane zachowanie wyżej na Mac OS X i kilku różnych dystrybucji Linksa.]


Edit: Mam scharakteryzowały podstawowy problem powyżej. W toku dalszych badań jest to wezwanie głównego wątku do join(), które uniemożliwia obsługę sygnałów: sam Guido van Rossum wyjaśnił, że the underlying lock acquire in join is uninterruptible. Oznacza to, że sygnał jest rzeczywiście odroczone do wykończenia całego wątku - tak naprawdę to nie ma nic wspólnego z raw_input na wszystkich (tylko fakt, że wątek tło blokuje tak, że połączenie nie zakończy).

+3

Nie łączy się tylko wątków i przerwań ... [boromir.jpg] – JBernardo

Odpowiedz

0

Jest to naprawdę nie jest łatwy sposób obejść ten problem, kropka.

Jednym ze sposobów jest reorganizacja i rozbicie kodu w taki sposób, że części funkcji wymagających interwencji są wykonywane na głównym wątku. Kolejek używasz do wysyłania żądań wykonania i podobnie do wartości wyników. Potrzebujesz jednej kolejki wejściowej dla głównego wątku i jednej kolejki wyjściowej dla wątku innego niż główny; i skoordynowane wyjście głównego wątku. Oczywiście, tylko jedna funkcja blokująca jest wykonywana w danym momencie w ten sposób, co może nie być tym, czego potrzebujesz.

Here's a working example of this idea z nieco przewrotny stosowania semaforów skoordynowanego głównego wyjścia gwintów.

3

Kiedy dołączyć nazywa bez limitu czasu, to jest bezprzerwowe, ale kiedy to się nazywa z limit czasu, to jest nieprzerwany. Spróbuj dodać arbitralny limit czasu i wstaw go w pętli:

while my_thread.isAlive(): 
    my_thread.join(5.0)