2011-02-05 20 views
6

Sto lavorando su un incarico che usa i segnali per trasferire un messaggio binario tra due processi, con l'obiettivo di conoscere i segnali (è uno strano uso).Perché il mio gestore di segnale non viene chiamato?

Nel mio programma, i due processi comunicano un codice, quindi uno trasferisce un messaggio all'altro. SIGUSR1 rappresenta 0, SIGUSR2 rappresenta 1. L'idea è che il processo che invia il messaggio utilizzi la funzione kill con qualsiasi SIGUSR per ricevere il messaggio, e il processo di ricezione avrà un gestore di segnali per interpretare i codici.

Quindi ecco il problema. Ho avviato il mittente. dorme mentre attende il codice da inviare. Il ricevitore invia due SIGINT per indicare la 'password', utilizzando pidof(8) per trovare il pid del mittente.

Una volta che il gestore del segnale del mittente ha letto questi segnali, riconosce che è la password corretta, quindi procede all'invio del messaggio.

Il ricevitore ha subito alcune funzioni e sta dormendo ogni secondo in attesa che ogni bit venga passato tramite un'interruzione. Il problema è che questo non succede mai.

ho creato in modo tale che il mittente invia un bit (0 in questo caso) in questo modo:

kill(SIGUSR1,washingtonPID); 

dove washingtonPID è il PID del ricevitore, e ho verificato questo è il corretto PID.

gestore del ricevitore è collegato in questo modo:

//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; 
} 

cui bit è una variabile globale. è inizialmente impostato su -1.

Qui è la funzione che legge i bit:

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

Quindi la corsa di base attraverso questo: Dopo che il codice è stato inviato dal ricevitore al mittente, il mittente inizia a inviare segnali uccidere di USR1 e USR2 al ricevitore, che alla fine dovrebbe formare un messaggio binario.

Il ricevitore sta semplicemente aspettando a questo punto, dormendo ogni secondo. Quando viene interrotto, il gestore imposterà bit a 0 o 1, tirandolo fuori dal sonno, stampando il bit e restituendolo.

se lascio i due programmi eseguiti normalmente, il ricevitore si trova proprio di sonno, e il gestore non è mai chiamato (anche se posso vedere le chiamate effettuate dal l'altro processo.

se mi fermo il mittente e inviando manualmente i segnali di Kill, posso inviare uno, forse due segnali, entrambi gestiti correttamente, dopodiché, e ricevo un messaggio stampato sul terminale come "segnale utente 2". Che non è qualcosa che ho nel mio programma e il programma si interrompe immediatamente

Qualsiasi intuizione sul perché il mio gestore non viene invocato, e sul motivo per cui non posso inviare manualmente più di uno o due segnali, sarebbe molto apprezzato

Grazie per il vostro tempo.

MODIFICA: Sembra che le persone siano perplesse su questo. Ci sono suggerimenti per il debug che potrei provare?

+0

Tutto quello che posso dire è che questo è un design ridicolmente inefficiente, e l'uso di 'pidof' per trovare un processo non è sicuro o robusto. (Immagina che qualcuno faccia un processo con lo stesso nome per rubare la password.) Dovresti usare socket di dominio UNIX per questo tipo di comunicazione. –

+3

Se noterai nel primo paragrafo, ho menzionato che questo è un compito e non un problema del mondo reale. È inefficiente e usare pidof non è sicuro. Ma non sono preoccupato per quello. – Blackbinary

+1

'bit' dichiarato' volatile'? –

risposta

5

Come molti hanno già commentato, non si dovrebbe fare questo con i segnali. Quando va male (e lo farà, come ha fatto) cercando di scoprire cosa c'è di sbagliato quando dietro a un comportamento indefinito è difficile se non impossibile.

L'utilizzo di chiamate di sistema non asincrone come fprintf all'interno dei gestori di segnale può danneggiare i dati poiché fprintf opera nello stesso flusso. Lo stesso con le variabili condivise.

Poiché si utilizza Linux, i segnali dello stesso tipo non verranno bloccati, il che significa che la consegna rapida dello stesso segnale può comportare una chiamata ricorsiva al gestore. Quando viene rilevato un segnale, la disposizione del segnale viene reimpostata su SIG_DFL e deve essere ristabilita nuovamente nel gestore (che può anche non riuscire se il segnale viene eliminato prima che venga ripristinata la modifica).

Ecco perché è possibile inviare un massimo di 1 segnale dello stesso tipo prima che il segnale venga ripristinato sui valori predefiniti e terminato il programma con "segnale utente xx".

Ti consiglio di smetterla di tormentarti con il codice e di prendere qualche libro di testo o un tutorial e provare a seguirlo.

Anche la chiamata del segnale dovrebbe essere evitata. Dalle pagine man:

Il comportamento del segnale() varia tra versioni di UNIX, e ha anche vario storicamente tra le diverse versioni di Linux . Evita l'uso: usa invece la sigaction (2).

+2

Apprezzo l'onestà. Mi rendo conto che dovrei usare funzioni diverse, e sigaction invece di segnale, ma questo è un corso e ho bisogno di limitarmi alle linee guida. C'è un modo per inviare segnali dello stesso tipo in fila? E se avessi dormito più a lungo tra i segnali, sarebbe stato d'aiuto? O dovrei forse usare un segnale di riempimento che ignoro sempre tra ogni segnale normale? – Blackbinary

+1

In realtà mi hai dato la risposta, ho dovuto leggere più in dettaglio. Come hai detto, una volta che un segnale viene catturato, ritorna a SIG_DFL, quindi questo significa che ogni volta che inserisco la mia funzione che dormirà, ho semplicemente impostato il 'segnale (SIGUSR1, gestore)' per garantire che il gestore non sia SIG_DFL. – Blackbinary

0

Un paio di cose che noto.

  • Qualsiasi variabile condivisa utilizzata nei gestori di segnale deve essere impostata come volatile.
  • fprintf() non è una funzione sicura da utilizzare in un gestore di segnale. Controlla la tua pagina man per signal() per ottenere un elenco delle funzioni sicure.
  • Inoltre, signal() ha un paio di implementazioni differenti per se un gestore di segnale viene reimpostato su SIG_DFL dopo essere stato attivato. La maggior parte dei Unix consiglia di utilizzare sigaction() per assicurarsi di ottenere il comportamento desiderato. O per testare si potrebbe ripristinare il gestore di segnale all'interno del gestore stesso, vedere se questo ti dà un comportamento diverso.
+0

Per quanto riguarda il motivo per cui il tuo mittente non funziona, scriverò un po 'di debug per vedere se a) la tua variabile "washingtonPID" è ciò che pensi sia, e controlla il ritorno della routine kill(). Assicurati che li stai eseguendo entrambi come lo stesso utente e nessuno dei due è impostato su un altro utente. – CoreyStup

+1

Ho ottenuto il mio mittente di lavoro, è solo il bug con il gestore predefinito afferrare i segnali dopo 1 o due segnali. – Blackbinary

Problemi correlati