2008-11-07 17 views
20

Estoy escribiendo una aplicación que bloquea en las aportaciones de dos istreams.Matar a un Boost bloqueado :: Tema

La lectura de istream es una llamada síncrona (de bloqueo), así que decidí crear dos Boost::thread para realizar la lectura.

Cualquiera de estos hilos puede llegar al "fin" (basado en alguna entrada recibida), y una vez que se alcanza el "fin", ambos flujos de entrada dejar de recibir. Lamentablemente, no puedo saber cuál será el motivo.

Por lo tanto, no puedo join() en ambos hilos, porque solo un hilo (no se puede predeterminar cuál) realmente devolverá (desbloqueará).

que de alguna manera debe forzar al otro a salir, pero es detenido a la espera de la entrada, por lo que no puede decidir por sí mismo es el momento de volver variables de condición (o lo que sea).

Es su manera a cualquiera:

  • enviar una señal de un impulso :: hilo, o
  • forzar una istream a "quebrar", o
  • matar a un impulso :: hilo?

Nota:

  • Uno de los istreams es cin
  • Estoy tratando de reiniciar el proceso, por lo que no se puede cerrar el flujo de entrada de una manera que les prohíbe reseteo.

Editar:

  • Yo sé cuando se alcanza el "fin", y yo no sé por cuál de ellos ha finalizado con éxito, y que debe ser matado. Es el asesinato que necesito descubrir (o una estrategia diferente para leer de un istream).
  • necesito ambos hilos para salir y limpiar adecuadamente :(

Gracias!

Respuesta

4

No creo que hay una manera de hacerlo multiplataforma, sino pthread_cancel debería ser lo que busca . con un hilo de impulso se puede obtener el native_handle de un hilo, y llamar a pthread_cancel en él.

Además de una mejor manera podría ser utilizar el impulso asio equivalente a una llamada de selección en varios archivos. de esa manera un hilo se bloquearse esperando la entrada, pero podría provenir de cualquier entrada eam. Sin embargo, no sé cuán fácil es hacer algo como esto con iostreams.

+0

Afortunadamente, estoy desarrollando una máquina Linux por ahora, pero preferiría una versión portátil. ¡Gracias por esto! – mmocny

+0

pthread_cancel() no lo hace para mí en un escenario similar, ni siquiera establece su tipo de cancelación en ASINCRONUS. – gatopeich

0

lugar de tratar de matar a su hilo, siempre se puede tryjoin el hilo en su lugar, y si falla, se unan a la otra en su lugar. (Suponiendo que siempre podrá unir al menos uno de sus dos hilos).

En alza: el hilo que busca la función timed_join.

Si quiere ver la respuesta correcta, sin embargo, eso sería usar io no bloqueante con esperas temporizadas. Permitiéndole obtener la estructura de flujo de io sincrónico, con el no bloqueo de io asíncrono.

Hablas de la lectura de istream, pero istream es solo una interfaz. para stdin, puede simplemente cerrar el descriptor de archivo stdin para interrumpir la lectura. En cuanto a la otra, depende de dónde esté leyendo desde ...

+0

¿Alguna sugerencia sobre cómo hacer esto? Tenía la impresión de que era imposible (para hacer esto de forma portátil) con cin. Y ya mencioné que me estoy uniendo a un hilo correctamente, es el otro con el que tengo que lidiar. Gracias sin embargo. – mmocny

+0

Una vez más, gracias. Pero creo que estás malinterpretando la pregunta. Uno de los hilos nunca se unirá(). Sé cómo conseguir uno de los hilos para unirme, e identificar el que no. Lo que necesito es sacar el otro hilo para desbloquear. (O piensa en una solución diferente) – mmocny

0

En Windows, use QueueUserAPC para poner en cola un proceso que genere una excepción. Ese enfoque funciona bien para mí.

SIN EMBARGO: Acabo de descubrir que los aumentos mutágenos, etc., no se "alertan" en win32, por lo que QueueUserAPC no puede interrumpirlos.

1

Bueno en Linux, uso pthread_signal (SIGUSR1), ya que interrumpe el bloqueo de IO. No hay tal llamada en Windows como descubrí al portar mi código. Solo una obsoleta en la llamada de lectura de socket. En Windows, debe definir explícitamente un evento que interrumpirá su llamada de bloqueo. Entonces, no existe tal cosa (AFAIK) como una forma genérica de interrumpir el bloqueo de IO.

El diseño del hilo boost maneja esto administrando puntos de interrupción bien identificados. No sé boost.asio bien y parece que no quiere confiar en él de todos modos. Si no desea refactorizar para usar un paradigma no bloqueante, lo que puede hacer es usar algo entre no bloqueo (sondeo) y bloqueo de IO. Esto es hacer algo como (pseudo código?):

while(!stopped && !interrupted) 
{ 
    io.blockingCall(timeout); 
    if(!stopped && !interrupted) 
    { 
     doSomething(); 
    } 
} 

Entonces se interrumpe sus dos hilos y se unen a ellos ...

Tal vez es más simple en su caso? Si tiene un hilo maestro que sabe que un hilo ha terminado, solo tiene que cerrar el IO del otro hilo.

Editar: Por cierto estoy interesado en la solución final que tiene ...

0

Parece que los hilos no están ayudando a hacer lo que quiere de una manera sencilla. Si Boost.Asio no es de su agrado, considere usar select().

La idea es obtener dos descriptores de archivos y utilizar select() para indicarle cuál de ellos tiene entradas disponibles. El descriptor de archivo para cin es típicamente STDIN_FILENO; cómo obtener el otro depende de sus detalles (si es un archivo, solo open() en lugar de usar ifstream).

Llame al select() en un bucle para saber qué entrada leer, y cuando quiera parar, simplemente salga del bucle.

4

Sí, lo hay!

boost::thread::terminate() hará el trabajo a sus especificaciones.

Hará que el subproceso dirigido arroje una excepción. Suponiendo que no se detecta, la pila se desenrollará correctamente destruyendo todos los recursos y terminando la ejecución del hilo.

La terminación no es instantánea. (El hilo equivocado se está ejecutando en ese momento, de todos modos.)

Ocurre en condiciones predefinidas: la más conveniente para usted sería probablemente al llamar al boost::this_thread::sleep();, que podría tener ese hilo periódicamente.

+0

¿De qué estás hablando? El __boost__ no tiene una función como 'boost :: thread :: terminate()'. –

+1

Hola, @YagamyLight. No estoy seguro de si realmente quieres una respuesta, pero puedes publicar una pregunta con respecto a lo que sucedió con 'boost :: thread :: terminate' después de escribir esta respuesta. –

4

Si un hilo de refuerzo se bloquea en una operación de E/S (por ejemplo, cin>>whatever), boost::thread::terminate() no matará el hilo. cin i/o no es un punto de terminación válido. Catch 22.

1

que tenía un problema similar a mí mismo y han llegado a esta solución, que algunos otros lectores de esta pregunta podrían serle de utilidad:

Suponiendo que está utilizando una variable de condición con un comando wait(), se es importante que sepa que en Boost, la instrucción wait() es un punto de interrupción natural. Así que simplemente coloque un bloque try/catch alrededor del código con la instrucción wait y permita que la función termine normalmente en su bloque catch.

Ahora, suponiendo que tiene un contenedor con sus punteros de hilo, repita los punteros de hilo y llame a interrupt() en cada hilo, seguido de join().

Ahora todos sus subprocesos terminarán correctamente y cualquier limpieza de memoria relacionada con Boost debería funcionar limpiamente.

0

Muy tarde, pero en Windows (y es precursores como VMS o RSX para aquellos que cuentan con tales cosas) usaría algo como ReadFileEx con una rutina de finalización que señala cuando termine, y CancelIO si la lectura necesita ser cancelada temprano.

Linux/BSD tiene una API subyacente completamente diferente que no es tan flexible. Usar pthread_kill para enviar una señal funciona para mí, eso detendrá la operación de lectura/apertura.

Vale la pena implementar un código diferente en esta área para cada plataforma, en mi humilde opinión.