2013-03-19 19 views
5

Ecco il problema: questo programma dovrebbe ricevere input da stdin e contare i byte inseriti; il segnale SIGUSR1 interromperà il programma principale e stamperà su file errore standard quanti byte sono stati copiati quando invio SIGUSR1.Il gestore di segnale non vedrà la variabile globale

Ecco come il mio insegnante mi vuole fare questo: in un solo tipo di terminale

cat /dev/zero | ./cpinout | cat >/dev/null 

mentre da un secondo terminale inviare segnali con

kill -USR1 xxxx 

dove xxxx è il PID del cpinout.

ho aggiornato il mio codice precedente:

/* cpinout.c */ 

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include <signal.h> 

#define BUF_SIZE 1024 

volatile sig_atomic_t countbyte = 0; 
volatile sig_atomic_t sigcount = 0; 

/* my_handler: gestore di signal */ 
static void sighandler(int signum) { 
    if(sigcount != 0) 
     fprintf(stderr, "Interrupted after %d byte.\n", sigcount); 
    sigcount = contabyte; 
} 

int main(void) { 

    int c; 
    char buffer[BUF_SIZE]; 
    struct sigaction action; 

    sigemptyset(&action.sa_mask); 
    action.sa_flags = 0; 
    action.sa_handler = sighandler; 
    if(sigaction(SIGUSR1, &action, NULL) == -1) { 
     fprintf(stderr, "sigusr: sigaction\n"); 
     exit(1); 
    } 
    while(c=getc(stdin) != EOF) { 
     countbyte++; 
     fputc(c, stdout); 
    } 
    return(0); 
} 
+0

non funzionerà anche con sigaction> elmazzun

risposta

2


EDIT

Nei commenti che hai menzionato che si esegue il comando come:

cat /dev/zero | ./namefile | cat >/dev/null

Il comportamento è in realtà bene. /dev/zero è un flusso infinito di zeri, che vengono inviati al programma. Quindi li conta molto rapidamente. Quando interrompi, si ferma e ti rimane un numero elevato.


Il problema può essere correlato al fatto che il gestore di segnale può essere chiamato mentre la variabile globale viene aggiornato (se questo richiede più di un'istruzione). Tuttavia, la documentazione GNU afferma che è lecito ritenere che uno int sia sempre atomico su un sistema POSIX.

L'unica altra possibilità che posso pensare è che si sta chiamando fputc nel circuito, con printf nel gestore (che dovrebbe comunque essere sicuro di chiamare printf in un gestore se non è stato chiamato dal programma). Prova a rimuovere fputc dal ciclo per vedere se risolve il problema.

EDIT:

Questo sembra spiegare il problema. Ciò si riferisce al tipo di funzioni che sono sicuri per chiamare dall'interno di un gestore di segnale:

funzioni possono anche essere nonreentrant se utilizzano strutture di dati statici per la loro contabilità interna.Gli esempi più evidenti di tali funzioni sono i membri della libreria stdio (printf(), scanf(), e così via), che aggiornano le strutture di dati interne per l'I/O bufferizzato. Pertanto, quando si utilizza printf() da un gestore di segnale, è possibile che visualizzi talvolta un output strano o addirittura un arresto anomalo del programma o dati danneggiato se il gestore interrompe il programma principale nel mezzo di eseguire una chiamata a printf () o un'altra funzione stdio. (The Linux Programming Interface)

del programma in corso interrompendo una funzione stdio, che sembra adattarsi perfettamente.


Ecco un approccio alternativo:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <signal.h> 

int countbyte = 0; // for main program 
int sigcount = 0; // for signal handler 

/* my_handler: signal handler */ 
static void sighandler(int signum) 
{ 
    sigcount = countbyte; 
} 

int main(void) 
{ 
    int c; 
    struct sigaction sigact; 

    sigemptyset(&sigact.sa_mask); 
    sigact.sa_flags = 0; 
    sigact.sa_handler = sighandler; 
    sigaction(SIGUSR1, &sigact, NULL); 
    while ((c = getc(stdin)) != EOF) { 
     countbyte++; 
     fputc(c, stdout); 
    } 
    if (sigcount != 0) { 
     printf("Interrupted after %d bytes\n", sigcount); 
    } 

    return 0; 
} 
+0

Può fare un suggerimento perché si pensa le differenze tra il segnale e il sigaction sono pertinenti qui.? – AProgrammer

+0

@AProgrammer - la documentazione afferma 'Il comportamento di signal() varia tra le versioni UNIX e varia anche storicamente tra le diverse versioni di Linux. Evita il suo uso: usa sigaction (2) invece ... L'unico uso portatile di signal() è quello di impostare la disposizione di un segnale a SIG_DFL o SIG_IGN. La semantica quando si usa signal() per stabilire un gestore di segnale varia tra i sistemi (e POSIX.1 consente esplicitamente questa variazione); ** non utilizzarlo a questo scopo. ** – teppic

+1

Sì, ci sono differenze di comportamento tra le varianti di unix, non ne conosco nessuna correlata al problema segnalato. – AProgrammer

3

I segnali possono scrivere solo volatile sig_atomic_t variabili in base alla C89 e POSIX 7 standard:

il comportamento è indefinito se il gestore del segnale si riferisce a qualsiasi oggetto [ CX] [Option Start] tranne errno [Option End] con durata dell'archiviazione statica diversa dall'assegnazione di un valore a un oggetto dichiarato come volatile sig_atomic_t

Spesso le implementazioni offrono di più, ma dubito che l'utilizzo di variabili globali non volatili o di printf sia qualcosa che è stato fornito dal vostro.