¿Cómo interrumpir una llamada fread?

8 minutos de lectura

avatar de usuario
pedro fortuna

tengo la siguiente situacion:

Hay un hilo que lee desde un dispositivo con una llamada fread. Esta llamada se bloquea mientras no se envíen datos desde el dispositivo. Cuando detengo este hilo, permanece colgando dentro de este hilo.

Ahora encontré lo siguiente dentro de la página man de fread:

ERRORES

En todos los sistemas que se ajustan a la especificación UNIX única, la función fread() establece errno como se indica para las siguientes condiciones:

[EINTR] La operación de lectura finalizó debido a la recepción de una señal y no se transfirieron datos.

Eso significaría que hay una manera de interrumpir la llamada desde un hilo diferente. Pero no tengo idea de cómo. ¿Alguien puede decirme cómo enviar una señal para interrumpir la llamada fread? ¿Y qué señal necesito enviar?


Actualización 08-10-10 09:25

Todavía no tengo que hacerlo funcionar. Probé kill() y pthread_kill() con diferentes señales. Pero nada parece interrumpir la llamada fread(). Lo único que funcionó fue eliminar toda la aplicación, pero eso no es lo que quiero.

  • Interesante que esto tenga que ver con la concurrencia: leí mal fread como un “hilo” cockney.

    – Jon Purdy

    7 oct 2010 a las 14:14

  • use lectura en lugar de fread

    – yuanjianpeng

    6 de agosto de 2021 a las 9:05

avatar de usuario
slezica

1. Señales:

Usar señales, como muchos otros señalaron, funcionaría. Sin embargo, como muchos otros también señalaron, el enfoque tiene sus desventajas.

2. Seleccionar():

Con select() (u otra función de multiplexación), puede bloquear la espera de que lleguen datos de más de un descriptor de archivo y especificar un tiempo de espera.

Utilice el tiempo de espera a su favor. Siempre que select() regrese, verifique una variable global para ver si debe terminar. Si quieres una reacción inmediata, sigue leyendo.

3. Select() y canalizaciones:

Múltiples fds significa que puede esperar a que lleguen los datos a través del dispositivo que mencionó y, por ejemplo, una tubería.

Antes de crear el subproceso, cree una tubería y luego haga que el subproceso se bloquee en select() para monitorear tanto el dispositivo como la tubería. Siempre que desee desbloquear, seleccione si el dispositivo tiene datos nuevos o no, envíe un byte por la tubería.

Si select() le dice que se desbloqueó debido a que los datos llegan a través de la canalización, puede limpiar y terminar. Tenga en cuenta que este método es mucho más flexible que el método de señalización, ya que puede, además de usar la tubería como método de activación, usarlo para pasar información o comandos útiles.

4. Select(), tuberías y señales:

Si está utilizando varios procesos y no quiere/no puede pasar por una tubería, puede combinar ambas soluciones. Cree una canalización e instale un controlador de señal para, por ejemplo, SIGUSR1. En el controlador de señal, envíe un byte por la tubería.

Siempre que un proceso envíe SIGUSR1, se llamará al controlador y se desbloqueará select(). Al examinar los fdsets, sabrá que no fue por otra razón que su propio programa señalándose a sí mismo.

  • no lo haría select() ser insuficiente porque fread() podría hacer varias llamadas a read()? Me pregunto si tal vez funcionaría hacer que la transmisión entre en un estado de error en un controlador de señal…

    – binki

    20 de septiembre de 2015 a las 0:13

Tienes muchas ganas de leer sobre el select(2) llamada al sistema, que le permitirá averiguar si hay datos disponibles en ese descriptor de archivo, sin bloquear en absoluto o sin bloquear solo en ese dispositivo.

  • Si bien select() sería útil, en realidad no responde la pregunta.

    –Michael Foukarakis

    7 oct 2010 a las 15:56

  • @Michael Foukarakis – Dado el contexto, la pregunta puede ser preguntar por el solución incorrecta al problema más grande. John dio una respuesta razonable para ayudar al OP a alcanzar su objetivo al abordar el problema más amplio. Downvote parece un poco duro.

    – bstpierre

    7 oct 2010 a las 16:26

  • No puedo juzgar la solución sin conocer el problema, ¿verdad? Tal vez el OP posee usar fread(). No lo sé, y prefiero no asumirlo.

    –Michael Foukarakis

    7 oct 2010 a las 16:58

  • fread está amortiguado, por lo que select podría bloquearse indefinidamente aunque haya datos disponibles para leer

    – Mark K. Cowan

    31 de octubre de 2016 a las 12:19

Echa un vistazo a man 2 kill. (O ver aquí)

Sin embargo, tengo la sensación de que no quieres hacer esto, la mayoría de las veces la gente ignora errno EINTR y lee de nuevo. Es posible que desee buscar lecturas sin bloqueo en su lugar.

  • ¿Puede decirme qué señal debo enviar con la llamada al sistema kill() para interrumpir el fread()?

    -Peter Fortuin

    7 oct 2010 a las 14:44

  • En términos generales, cualquier señal interrumpirá el fread() llamar. Dicho esto, en términos generales, muchas señales también eliminarán su aplicación (excepto SIGCONT). Usaría SIGHUP o una de las señales definidas por el usuario personalmente. Pero como dije en mi respuesta, tampoco me gusta usar señales para este propósito. (Vea la respuesta de John Marshall para una alternativa)

    – Platino Azur

    7 oct 2010 a las 15:32

  • Además de generar una señal de otro hilo con killla alarm La función se usa a menudo para causar un bloqueo. read llamar al tiempo de espera.

    – Ben Voigt

    7 oct 2010 a las 18:43

  • @Ben Voigt: sí, y sigo pensando que es feo cada vez que lo veo.

    – ninjalj

    7 oct 2010 a las 22:42

  • @ninjalj: No estoy en desacuerdo contigo, prefiero usar poll o aio, que tienen todos los beneficios de select sin la torpe lógica de configuración de argumentos. Pero es útil conocer patrones como el uso de alarm para establecer un tiempo de espera en una llamada de E/S de bloqueo para que los reconozca al leer el código existente.

    – Ben Voigt

    8 de octubre de 2010 a las 0:11

avatar de usuario
bstpierre

En el hilo, en lugar de bloquear con freadbloquear con select. Cuando select devuelve, marque una variable “ya terminé”. Si no lo hace, puede llamar fread para obtener los datos.

Desde el otro subproceso, que quiere detener el subproceso fread, puede configurar la variable “ya terminé” y luego cerrar el fd para que el subproceso fread se despierte. select inmediatamente.

Si su contexto le prohíbe cerrar el fd (menciona que está leyendo desde un dispositivo, pero dice que tenía un socket que quería mantener abierto), podría abrir un segundo fd en el que escribe desde el otro hilo para despertar select.

Como se sugiere en los comentarios a continuación, cerrar el fd para despertar select puede que no sea portátil. Puede usar la estrategia second-fd mencionada anteriormente para lograr esto de manera más portátil.

avatar de usuario
Oliver Charlesworth

Puedes usar el matar() llamada al sistema.

ACTUALIZAR

Resulta que leí mal tu pregunta. Como R. señaló a continuación, kill() es solo para matar procesos, no hilos.

  • ¿Puede decirme qué señal debo enviar con la llamada al sistema kill() para interrumpir el fread()?

    -Peter Fortuin

    7 oct 2010 a las 14:42

  • Tiene que ser una señal para la que haya configurado previamente un controlador de señal (ver sigaction()) y tiene no usé la SA_RESTART bandera.

    – marca4o

    7 oct 2010 a las 16:45

  • kill no trabajará. Necesitas pthread_kill que puede enviar la señal a un hilo específico.

    – R.. GitHub DEJA DE AYUDAR A ICE

    8 de octubre de 2010 a las 6:52

  • kill() está bien si la señal está bloqueada en los otros subprocesos.

    – marca4o

    9 de octubre de 2010 a las 3:37

avatar de usuario
R.. GitHub DEJAR DE AYUDAR A ICE

Los controladores de señales no interrumpirán fread a menos que se hayan instalado como interruptores, y las señales no controladas nunca interrumpen. El estándar POSIX permite que los manipuladores instalados por el signal función para interrumpir o no interrumpir de forma predeterminada (y en Linux el valor predeterminado para no interrumpir), por lo que si necesita un comportamiento específico, use el sigaction función y especificar la deseada sa_flags. En particular, debe omitir el SA_RESTART bandera. Por ejemplo:

struct sigaction sa = { .sa_handler = dummy_func, .sa_flags = 0 };
sigaction(SIGUSR1, &sa, 0);

Tenga en cuenta que sa_flags sería implícitamente 0 de todos modos si se omite, pero lo incluí explícitamente en el inicializador para ilustrar. Entonces puedes interrumpir el fread enviando SIGUSR1 con kill o pthread_kill.

  • ¿Puede decirme qué señal debo enviar con la llamada al sistema kill() para interrumpir el fread()?

    -Peter Fortuin

    7 oct 2010 a las 14:42

  • Tiene que ser una señal para la que haya configurado previamente un controlador de señal (ver sigaction()) y tiene no usé la SA_RESTART bandera.

    – marca4o

    7 oct 2010 a las 16:45

  • kill no trabajará. Necesitas pthread_kill que puede enviar la señal a un hilo específico.

    – R.. GitHub DEJA DE AYUDAR A ICE

    8 de octubre de 2010 a las 6:52

  • kill() está bien si la señal está bloqueada en los otros subprocesos.

    – marca4o

    9 de octubre de 2010 a las 3:37

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad