2012-02-13 11 views
5

En un programa de Python multiproceso, un hilo a veces solicita la entrada de la consola con el raw_input() incorporado. Me gustaría poder cerrar el programa mientras estoy en un indicador raw_input escribiendo^C en el shell (es decir, con una señal SIGINT). Sin embargo, cuando el subproceso secundario está ejecutando raw_input, al escribir^C no se hace nada - KeyboardInterrupt no se activa hasta que pulso return (dejando raw_input).Interrumpir Python raw_input() en un hilo secundario con^C/KeyboardInterrupt

Por ejemplo, en el siguiente programa:

import threading 

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

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

Typing^C no hace nada hasta después de la entrada está terminado. Sin embargo, si simplemente llamamos al T().run() (es decir, el caso de un solo subproceso: simplemente ejecuta la entrada raw_input en el hilo principal),^C cierra el programa inmediatamente.

Presumiblemente, esto se debe a que SIGINT se envía al hilo principal, que se suspende (esperando el GIL) mientras se lee el bloque de hilos bifurcados en la consola. El hilo principal no puede ejecutar su manejador de señal hasta que agarra el GIL después de que retorna raw_input. (Corrígeme si me equivoco al respecto; no soy un experto en la implementación de subprocesos de Python).

¿Hay alguna forma de leer desde stdin en una forma raw_input al tiempo que permite administrar SIGINT? por el hilo principal y así reducir todo el proceso?

[He observado el comportamiento anterior en Mac OS X y unos Linuxes diferentes.]


Editar: que he descrito erróneamente el problema subyacente anteriormente. En una investigación más a fondo, es el llamado del hilo principal al join() el que está impidiendo el manejo de señales: el propio Guido van Rossum ha explicado que the underlying lock acquire in join is uninterruptible. Esto significa que la señal en realidad se está aplazando hasta que finalice todo el hilo, por lo que esto realmente no tiene nada que ver con raw_input (solo el hecho de que el hilo de fondo está bloqueado para que la unión no se complete).

+3

Uno no simplemente combina Threads and Interruptions ... [boromir.jpg] – JBernardo

Respuesta

0

Realmente no hay una manera fácil de evitar esto, punto.

Un enfoque consiste en reorganizar y dividir el código de forma que partes de las funciones que necesitan Ctrl-C interruptibility se ejecuten en el hilo principal. Utiliza colas para enviar solicitudes de ejecución y, asimismo, para los valores de resultado. Necesita una cola de entrada para el hilo principal y una cola de salida para cada hilo no principal; y una salida de hilo principal coordinada. Obviamente, solo se ejecuta una función de bloqueo en cualquier momento dado de esta manera, que puede no ser lo que usted desea.

Here's a working example of this idea con un uso ligeramente perverso de los semáforos para la salida coordinada de la rosca principal.

3

Cuando se llama a la unión sin tiempo de espera, es ininterrumpible, pero cuando se invoca con un tiempo de espera, es interrumpible. Intente agregar un tiempo de espera arbitrario y ponerlo en un bucle while:

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