Pregunta

Estoy escribiendo una aplicación que bloquea la entrada de dos istreams .

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

Cualquiera de estos hilos puede llegar al " final " (basado en alguna entrada recibida), y una vez que el " finalice se alcanza, ambas secuencias de entrada dejan de recibir. Desafortunadamente, no puedo saber cuál lo hará.

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

De alguna manera debo obligar al otro a salir, pero está bloqueado esperando la entrada, por lo que no puede decidir por sí mismo que es hora de regresar (variables de condición o no).

Es su forma de:

  • Enviar una señal a boost :: thread, o
  • Forzar un istream para " fail " ;, o
  • ¿Matar un Boost :: thread?

Nota:

  • Uno de los istreams es cin
  • Estoy tratando de reiniciar el proceso, por lo que no puedo cerrar las secuencias de entrada de una manera que prohíbe reiniciarlas.

Editar:

  • Sí sé cuando el " finaliza " se alcanza, y sé qué hilo ha finalizado con éxito, y cuál necesita ser eliminado. Es el asesinato lo que necesito descubrir (o una estrategia diferente para leer de un istream).
  • Necesito ambos hilos para salir y limpiar correctamente :(

¡Gracias!

¿Fue útil?

Solución

No creo que haya una manera de hacerlo multiplataforma, pero pthread_cancel debería ser lo que estás buscando. Con un hilo de impulso puede obtener el native_handle de un hilo, y llame a pthread_cancel en él.

Además, una mejor manera podría ser utilizar el impulso asio equivalente de una llamada selecta en varios archivos. De esa manera, un subproceso se bloqueará esperando la entrada, pero podría provenir de cualquier flujo de entrada. Sin embargo, no sé lo fácil que es hacer algo así con iostreams.

Otros consejos

¡Sí lo hay!

boost :: thread :: terminate () hará el trabajo según sus especificaciones.

Hará que el hilo objetivo arroje una excepción. Asumiendo que no está atrapado, 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 incorrecto se está ejecutando en ese momento, de todos modos).

Sucede en condiciones predefinidas; lo más conveniente para usted probablemente sería cuando llame a boost :: this_thread :: sleep (); , que podría hacer que ese hilo haga periódicamente.

Si un subproceso de impulso está bloqueando una operación de E / S (por ejemplo, cin > > lo que sea ), boost :: thread :: terminate () no matará la amenaza. cin i / o no es un punto de terminación válido. Captura 22.

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 uno en desuso en 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 boost.thread maneja esto administrando puntos de interrupción bien identificados. No conozco bien boost.asio y parece que no quieres confiar en él de todos modos. Si no desea refactorizar para usar el paradigma de no bloqueo, lo que puede hacer es usar algo entre no bloqueo (sondeo) y bloqueo de E / S. Es decir, hacer algo como (pseudocódigo):

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

Luego interrumpes tus dos hilos y los unes ...

¿Quizás es más simple en su caso? Si tiene un hilo maestro que sabe que un hilo está terminado, ¿solo tiene que cerrar el IO del otro hilo?

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

Tuve un problema similar y he llegado a esta solución, que algunos otros lectores de esta pregunta podrían encontrar útil:

Suponiendo que está utilizando una variable de condición con un comando wait (), 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 tenga 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 hilos terminarán con gracia y cualquier limpieza de memoria relacionada con Boost debería funcionar correctamente.

En lugar de intentar matar tu hilo, siempre puedes unirte al hilo, y si falla, te unes al otro. (Suponiendo que siempre podrá unir al menos uno de sus dos hilos).

En boost: thread está buscando el función timed_join .

Sin embargo, si desea ver la respuesta correcta, sería usar io sin bloqueo con esperas programadas. Permitiéndole obtener la estructura de flujo de io síncrono, con el no bloqueo de io asíncrono.

Usted habla de leer un istream, pero un istream es solo una interfaz. para stdin, puede simplemente cerrar el descriptor del archivo stdin para interrumpir la lectura. En cuanto al otro, depende de dónde estés leyendo ...

Parece que los hilos no te ayudan a hacer lo que quieres de una manera simple. Si Boost.Asio no es de su agrado, considere usar select () .

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

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

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

SIN EMBARGO : Acabo de descubrir que los mutexes de impulso, etc., no son "alertables". en win32, por lo que QueueUserAPC no puede interrumpirlos.

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

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top