2013-03-19 13 views
5

Hier ist das Problem: Dieses Programm sollte eine Eingabe von stdin erhalten und die eingefügten Bytes zählen; Das Signal SIGUSR1 stoppt das Hauptprogramm und gibt einen Standardfehler aus, wie viele Bytes beim Senden des SIGUSR1 kopiert wurden.Signal-Handler wird keine globale Variable sehen

Das ist, wie mein Lehrer will, dass ich dies tun: in einem Terminal-Typ

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

, während sie von einem zweiten Endgerät senden Signale mit

kill -USR1 xxxx 

wobei xxxx die pid von cpinout ist.

ich meine vorherigen Code aktualisiert:

/* 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

Wird mit sigaction nicht funktionieren sogar> elmazzun

Antwort

2


EDIT

In den Kommentaren Sie erwähnten, dass Sie den Befehl ausführen, wie:

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

Das Verhalten ist eigentlich in Ordnung. /dev/zero ist ein endloser Strom von Nullen, die an das Programm gesendet werden. Es zählt also sehr schnell. Wenn Sie unterbrechen, stoppt es und Sie sind mit einer großen Anzahl übrig.


Das Problem kann das Signal-Handler aufgerufen werden kann, während die globale Variable aktualisiert wird (falls diese mehr als einen Befehl nimmt) der Tatsache zusammenhängen, dass. Die GNU-Dokumentation besagt jedoch, dass davon auszugehen ist, dass ein int in einem POSIX-System immer atomar ist.

Die einzige andere Möglichkeit, die ich denken kann, ist, dass Sie fputc in der Schleife anrufen, mit printf im Handler (es sollte jedoch sicher seine printf in einem Handler zu nennen, wenn es durch das Programm nicht genannt werden). Versuchen Sie, aus der Schleife zu entfernen, um zu sehen, ob es das Problem behebt.

EDIT:

Dies scheint das Problem zu erklären. Dies bezieht sich auf die Art von Funktionen, die aus einem Signal-Handler sicher zu nennen sind:

Funktionen auch nonreentrant sein können, wenn sie Strukturen statische Daten für ihre internen Buchführung verwenden.Die offensichtlichsten Beispiele für solche -Funktionen sind die Mitglieder der stdio-Bibliothek (printf(), scanf(), usw.), die interne Datenstrukturen für gepufferte E/A aktualisieren. So, wenn wir printf() aus einem Signal-Handler verwenden, können wir manchmal seltsame Ausgabe sehen - oder sogar einen Programmabsturz oder Daten Korruption - wenn der Handler das Hauptprogramm in der Mitte von einem Aufruf von printf () oder eine andere stdio-Funktion. (Die Linux Programming Interface)

Ihr Programm ist eine stdio Funktion zu unterbrechen, die diese perfekt zu passen scheint.


Hier ist ein alternativer Ansatz:

#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

Könnten Sie einen Hinweis geben, warum Sie die Unterschiede zwischen Signal und sigaction denken sind hier relevant.? – AProgrammer

+0

@AProgrammer - die Dokumentation sagt 'Das Verhalten von signal() variiert zwischen UNIX-Versionen und hat sich auch historisch über verschiedene Versionen von Linux hinweg verändert. Vermeiden Sie seine Verwendung: Verwenden Sie stattdessen sigaction (2) ... Die einzige portable Verwendung von signal() besteht darin, die Disposition eines Signals auf SIG_DFL oder SIG_IGN zu setzen. Die Semantik bei der Verwendung von signal() zum Aufbau eines Signal-Handlers variiert systemübergreifend (und POSIX.1 erlaubt explizit diese Variation); ** Verwenden Sie es nicht für diesen Zweck. ** – teppic

+1

Ja, es gibt Unterschiede im Verhalten zwischen Unix-Varianten, ich kenne keine, die sich auf das gemeldete Problem beziehen. – AProgrammer

3

Signale nur volatile sig_atomic_t Variablen nach dem C89 und POSIX 7 Standards schreiben kann:

das Verhalten ist nicht definiert, wenn das Signal-Handler auf ein beliebiges Objekt verweist [ CX] [Option Start] anders als errno [Option Ende] mit statischer Speicherdauer anders als durch Zuweisung eines Werts zu einem als flüchtig deklarierten Objekt

Implementierungen bieten oft mehr, aber ich bezweifle, dass die Verwendung von nichtflüchtigen globalen Variablen oder printf etwas von Ihnen zur Verfügung gestellt wird.