2016-09-10 3 views
0

Ich möchte ein Programm in c für Linux schreiben, das das erste Signal SIGUSR1 abfängt, das zweite ignoriert und in diesem Verhalten (catch-ignore) für die aufeinanderfolgenden Signale SIGUSR1 fortfährt.wie fortwährend alternieren Signal Handler

Ich frage mich, wie man zwischen den beiden Handlern abwechselt, denn sobald ich den Handler auf SIG_IGN setze, wird das Signal ignoriert und ich kann es nicht erkennen und entsprechend handeln.

Dies ist der Code, den ich versucht habe:

int tst; 
void sigusr1_handler(){ 
    if(tst==0){ 
     signal(SIGUSR1,SIG_IGN); 
     tst=1; 
    } 
    else tst= 0; 
} 


int main(){ 
    signal(SIGUSR1, sigusr1_handler); 
    tst=1; 
    while(1){} 
return 0; 
} 
+1

Das Ignorieren eines Signals (normalerweise) führt zum Programmabbruch. Schlagen Sie immer: fangen Sie immer das Signal und verwenden Sie eine "statische" Variable, um festzustellen, ob der Code irgendetwas mit der aktuellen Instanz des Signals macht. I.E. Die Signal-Handler-Funktion prüft/aktualisiert die statische Variable mit jedem empfangenen Signal. – user3629249

+0

das Problem ist, dass ich mit SIG_IGN wechseln muss. Wenn ich das Signal mit einer Signal-Handler-Funktion abfange, wird diese Funktion nicht ausgeführt, sobald der Signal-Handler zum ersten Mal auf SIG_IGN gesetzt wird. – Selma

+0

Fragen, die Debugging-Hilfe suchen ("Warum funktioniert dieser Code nicht?") Müssen das gewünschte Verhalten, ein bestimmtes Problem oder einen Fehler und den kürzesten Code enthalten, der für die Reproduktion in der Frage erforderlich ist. Fragen ohne eine klare Problemstellung sind für andere Leser nicht nützlich. Siehe: Erstellen eines minimalen, vollständigen und überprüfbaren Beispiels. – Olaf

Antwort

1

Sie dies nicht tun.

Was Sie tun können, ist Ihre Signal-Handler entscheiden, ob etwas zu tun oder nicht - zum Beispiel, ob eine andere Funktion oder nicht anrufen. Dies ist jedoch nicht vollständig zuverlässig, da standard POSIX signals wie SIGUSR1 nicht in der Warteschlange stehen. Wenn zwei oder mehr Signale zu (fast) der gleichen Zeit gesendet werden, wird nur eine tatsächlich geliefert. POSIX-Echtzeitsignale (SIGRTMIN+0 bis SIGRTMAX-0 - aus der Sicht des Programmierers unterscheiden sich nur die Anzahl und die Semantik) werden in die Warteschlange gestellt, aber selbst sie können in einigen Situationen fallen gelassen werden.

Denken Sie in jedem Fall daran, dass eine Signal-Handler-Funktion nur verwenden kann. Wenn Sie in der Lage sein müssen, alle Funktionen zu verwenden, sollten Sie stattdessen die Signale in allen Threads blockieren, und ein dedizierter Thread muss die Signale z. sigwaitinfo(). In diesem Fall haben Sie keine Signal-Handler-Funktionen, sondern einen dedizierten Thread, der die Signale empfängt und somit frei ist, beliebige Funktionen zu verwenden, die er will.

Wenn wir die Frage in umschreiben "Wie wechsele ich die Handhabung eines gelieferten Signals in einem single-threaded-Programm?", die Antwort ist einfach: Sie verwenden einen volatile sig_atomic_t Zähler.

Für das Wechseln zwischen zwei Wahlen, do_something_odd() zuerst:

#include <signal.h> 

void my_signal_handler(int signum) 
{ 
    static volatile sig_atomic_t count = 0; 

    switch (++count) { 

    case 1: 
     do_something_odd(); 
     break; 

    default: 
     count = 0; 
     do_something_even(); 
     break; 
    } 
} 

Für den Wechsel zwischen drei Fällen Sie mehr case Aussagen wie nötig hinzufügen:

#include <signal.h> 

void my_signal_handler(int signum) 
{ 
    static volatile sig_atomic_t count = 0; 

    switch (++count) { 

    case 2: 
     do_something_2_of_3(); 
     break; 

    case 1: 
     do_something_1_of_3(); 
     break; 

    default: 
     count = 0; 
     do_something_3_of_3()   
     break; 
    } 
} 

Die obige Sie die Signal-Handler installieren einnimmt mit sigaction() ohne SA_SIGINFO in .sa_flags.

Der POSIX-Standard besagt, dass Sie bis zu 128 Fälle bearbeiten können (da sig_atomic_t garantiert die Werte 0 bis einschließlich 127 darstellen kann).

Sie können größere Mengen tun, um eine unsigned int oder unsigned long verwenden, aber dann müssen Sie NICHT SA_NODEFER im .sa_flags haben, und wenn die gleiche Prozedur für mehrere Signale verwendet wird, muss die .sa_mask haben alle anderen von der gleichen Handler behandelt Signale einstellen. Dies stellt sicher, dass der Signal-Handler nicht durch ein anderes Signal unterbrochen wird, das an den gleichen Handler geliefert wird, und ermöglicht es uns, eine nicht-atomare Zählervariable zu verwenden.

In einem Multithread-Programm muss man sich auf vom Compiler bereitgestellte atomare Operationen verlassen, entweder Legacy __sync Built-Ins oder __atomic Built-Ins. Sie sind nicht GCC-spezifisch; zumindest Intel Compiler Collection und clang bieten sie auch an.Für den Wechsel zwischen zwei Optionen kann our = __atomic_xor_fetch(&counter, 1, __ATOMIC_SEQ_CST); oder our = __sync_xor_and_fetch(&counter, 1); verwendet werden, um einen Zähler zwischen 0 und 1 atomar zu erhalten und zu spiegeln. Für eine Anzahl von Optionen ohne Potenz von zwei wird typischerweise eine Vergleichs- und Austauschschleife verwendet.

Verwandte Themen