2011-02-05 9 views
6

Im trabajando en una tarea que utiliza señales para transferir un mensaje binario entre dos procesos, con el objetivo de aprender sobre las señales (de hecho, es un uso extraño).¿Por qué no se llama mi manejador de señal?

En mi programa, los dos procesos se comunican un código, y luego uno transfiere un mensaje a la otra. SIGUSR1 representa 0, SIGUSR2 representa 1. La idea es que el proceso que envía el mensaje utilizará la función de cancelación con cualquier SIGUSR para transmitir el mensaje, y el proceso de recepción tendrá un controlador de señal para interpretar los códigos.

Así que aquí es el problema. Tengo el remitente encendido. duerme mientras espera que se envíe el código. El receptor envía dos SIGINT para indicar la 'contraseña', usando pidof(8) para encontrar el pid del remitente.

Una vez manejador de la señal del remitente ha leído estas señales, reconoce que es la contraseña correcta, se procede a enviar el mensaje.

El receptor ahora ha pasado por unas pocas funciones, y está durmiendo cada segundo de espera para cada bit que se pasa a través de una interrupción. El problema es que esto nunca sucede.

he configurarlo de forma que el emisor está enviando un bit (0 en este caso), así:

kill(SIGUSR1,washingtonPID); 

donde washingtonPID es el PID del receptor, y he comprobado esto es la correcta PID.

manejador del receptor está conectado de esta manera:

//IN MAIN 
    signal(SIGINT,bitReceiver); 
    signal(SIGUSR1,bitReceiver); 
    signal(SIGUSR2,bitReceiver); 
//OUTSIDE MAIN 

    void bitReceiver(int signum) 
{ 
    if(signum == SIGUSR1) 
    { 
     fprintf(stderr,"SIGUSR1 - 0"); 
     bit = 0; 
    } 
    else if (signum == SIGUSR2) 
    { 
     fprintf(stderr,"SIGUSR2 - 1"); 
     bit = 1; 
    } 
    else //sigint 
    raise(SIGINT); 

    return; 
} 

donde el bit es una variable global. inicialmente se establece en -1.

Aquí es la función que lee los bits:

int receiveBit() 
{ 
    while(bit == -1) 
    { 
     sleep(1); 
    } 
    fprintf(stderr,"%d",bit); 
    int bit2 = bit; 
    bit = -1; 
    return bit2; 
} 

Así que la carrera básica por medio es la siguiente: Después de que el código ha sido enviado desde el receptor al emisor, el emisor comienza a enviar señales de finalización de USR1 y USR2 al receptor, que eventualmente debería formar un mensaje binario.

El receptor está simplemente esperando en este punto, durmiendo cada segundo. Cuando se interrumpe, el controlador establecerá el bit en 0 o 1, lo desactivará, imprimirá el bit y lo devolverá.

Si dejo los dos programas se ejecutan normalmente, el receptor sólo se sienta en el sueño, y el manejador nunca es llamado (a pesar de que puedo ver las llamadas que realiza el otro proceso.

si paro del remitente , y enviar manualmente las señales de Kill, puedo enviar una, tal vez dos señales, ambas manejadas correctamente. cualquiera después de eso, y recibo un mensaje impreso en la terminal como "señal de usuario 2". Lo cual no es algo que tenga en mi programa , y el programa se detiene inmediatamente.

Cualquier idea sobre por qué mi controlador no está siendo envidado, y por qué no puedo enviar manualmente más de una o dos señales sería muy apreciada.

Gracias por su tiempo.

EDIT: Parece que la gente se difuminan en esto. ¿Hay algún consejo para eliminar errores que pueda probar?

+0

Todo lo que puedo decir es que este es un diseño ridículamente ineficiente, y el uso de 'pidof' de encontrar un procedimiento que no es seguro o sólida. (Imagine que alguien realiza un proceso con el mismo nombre para robar la contraseña). Debería usar conectores de dominio UNIX para este tipo de comunicación. –

+3

Si nota en el primer párrafo, mencioné que esto es una tarea y no un problema del mundo real. Es ineficiente y el uso de pidof no es seguro. Pero no estoy preocupado por eso. – Blackbinary

+1

¿Se declara 'bit'' volátil'? –

Respuesta

5

Como muchos ya han comentado, no debería estar haciendo esto con señales en absoluto. Cuando sale mal (y lo hará, como lo hizo) tratando de averiguar qué está mal cuando hay un comportamiento indefinido detrás es difícil, si no imposible.

El uso de llamadas de sistema no asíncronas como fprintf dentro de controladores de señal puede dañar los datos ya que fprintf está funcionando en la misma secuencia. Lo mismo con las variables compartidas.

Dado que está utilizando Linux, las señales del mismo tipo no se bloquearán, lo que significa que la entrega rápida de la misma señal puede dar como resultado una llamada recursiva al controlador. Una vez que se capta una señal, la disposición de la señal se reinicia a SIG_DFL y necesita restablecerse en el controlador nuevamente (que también puede fallar si la señal se libera antes de que se restablezca el cambio).

Es por eso que puede enviar un máximo de 1 señal del mismo tipo antes de que la señal se restablezca a la predeterminada y finalice el programa con "señal de usuario xx".

Yo recomendaría que deje de atormentarse con el código y tome un libro de texto o un tutorial e intente seguir eso.

La llamada de señal también debe evitarse si se produce. De las páginas man:

El comportamiento de la señal() varía a través de versiones de Unix, y tiene también variada históricamente a través de diferentes versiones de Linux. Evite su uso: use sigaction (2) en su lugar.

+2

Aprecio la honestidad. Me doy cuenta de que debería usar diferentes funciones, y sigaction en lugar de señal, pero esto es trabajo de curso y necesito limitarme a las pautas. ¿Hay alguna manera de enviar señales del mismo tipo en una fila? ¿Qué pasa si duermo más tiempo entre las señales? ¿Eso ayudaría? ¿O debería usar una señal de relleno que siempre ignoro entre cada señal regular? – Blackbinary

+1

En realidad me has dado la respuesta, solo tenía que leer con más detalle. Como dijiste, una vez que se capta una señal, vuelve a SIG_DFL, por lo que cada vez que entro en mi función que dormirá, simplemente configuro la 'señal (SIGUSR1, manejador)' para asegurar que el manejador no sea SIG_DFL. – Blackbinary

0

Un par de cosas que noté.

  • Cualquier variable compartida utilizada en controladores de señal debe establecerse como volatile.
  • fprintf() no es una función segura para ser utilizada en un manejador de señal. Consulte la página de manual para signal() para obtener una lista de las funciones seguras.
  • también, signal() tiene un par de implementaciones diferentes para si un manejador de señal se restablece a SIG_DFL después de ser activado. La mayoría de los Unix sugieren usar sigaction() para asegurarse de obtener el comportamiento que desea. O para probar, puede reiniciar el manejador de señal dentro del manejador, vea si eso le da un comportamiento diferente.
+0

En cuanto a por qué su remitente no funciona, escribiría algunas depuraciones para ver si a) su variable "washingtonPID" es lo que cree que es, y verifique el retorno de la rutina kill(). Asegúrate de que estás ejecutando ambos como el mismo usuario y ninguno de los dos es setuid para otro usuario. – CoreyStup

+1

Tengo mi remitente funcionando, es solo el error de tener el controlador predeterminado tomar las señales después de 1 o dos señales. – Blackbinary

Cuestiones relacionadas