So verwenden Sie Signalhandler in der C -Sprache?

So verwenden Sie Signalhandler in der C -Sprache?
In diesem Artikel zeigen wir Ihnen, wie Sie Signalhandler unter Linux mit C -Sprache verwenden können. Aber zuerst werden wir diskutieren, was Signal ist, wie es einige gängige Signale erzeugt, die Sie in Ihrem Programm verwenden können, und dann werden wir so aussehen, wie verschiedene Signale von einem Programm behandelt werden können, während das Programm ausgeführt wird. So lass uns anfangen.

Signal

Ein Signal ist ein Ereignis, das generiert wird, um einen Prozess oder Faden zu benachrichtigen, dass eine wichtige Situation eingetroffen ist. Wenn ein Vorgang oder Thread ein Signal erhalten hat, stoppt der Prozess oder Thread, was er tut, und ergreifen einige Maßnahmen. Signal kann für die Kommunikation zwischen den Prozess nützlich sein.

Standardsignale

Die Signale sind in der Header -Datei definiert Signal.H als Makrokonstante. Der Signalname hat mit einer „SIG“ begonnen und gefolgt von einer kurzen Beschreibung des Signals. Jedes Signal hat also einen eindeutigen numerischen Wert. Ihr Programm sollte immer den Namen der Signale verwenden, nicht die Signalnummer. Der Grund ist, dass die Signalzahl nach System unterschiedlich sein kann, aber die Bedeutung von Namen ist Standard.

Das Makro NSIG ist die Gesamtzahl der definierten Signal. Der Wert von NSIG ist eine größer als die Gesamtzahl der definierten Signal (alle Signalzahlen werden nacheinander zugewiesen).

Im Folgenden finden Sie die Standardsignale:

Signalname Beschreibung
SEUFZEND Hängen Sie den Prozess auf. Das Seufzersignal wird verwendet, um die Trennung des Terminals des Benutzers zu melden, möglicherweise weil eine Fernverbindung verloren geht oder auflegt.
Sigint Den Prozess unterbrechen. Wenn der Benutzer das INTR -Zeichen eingibt (normalerweise Strg + C), wird das SIGINT -Signal gesendet.
Sigquit Beenden Sie den Prozess. Wenn der Benutzer das Quit -Zeichen (normalerweise Strg + \) eingibt, wird das Sigquit -Signal gesendet.
Sigill Illegale Anweisung. Wenn ein Versuch unternommen wird, Müll oder privilegierte Anweisungen auszuführen, wird das Sigill -Signal erzeugt. Außerdem kann Sigill erzeugt werden, wenn der Stapel überläuft oder wenn das System Probleme hat, einen Signalhandler auszuführen.
Sigtrap Trace -Falle. Eine Haltepunktanweisung und ein anderer Trap -Befehl erzeugt das SIGTRAP -Signal. Der Debugger verwendet dieses Signal.
Sigabrt Abbrechen. Das Sigabrt -Signal wird erzeugt, wenn abort () aufgerufen wird. Dieses Signal zeigt einen Fehler an, der vom Programm selbst erkannt und vom Funktionsaufruf von ABORT () gemeldet wird.
Sigfpe Schwebende Punktausnahme. Wenn ein tödlicher arithmetischer Fehler aufgetreten ist, wird das SIGFPE -Signal erzeugt.
Sigusr1 und Sigusr2 Die Signale Sigusr1 und Sigusr2 können nach Belieben verwendet werden. Es ist nützlich, einen Signalhandler für sie in das Programm zu schreiben, das das Signal für eine einfache Kommunikation zwischen den Prozess empfängt.

Standardaktion von Signalen

Jedes Signal hat eine Standardaktion, eines der folgenden:

Begriff: Der Prozess endet endet.
Kern: Der Prozess endet und erzeugt eine Kern -Dump -Datei.
IGN: Der Prozess ignoriert das Signal.
Stoppen: Der Prozess stoppt.
Fortsetzung: Der Prozess wird weiterhin gestoppt werden.

Die Standardaktion kann mithilfe der Handler -Funktion geändert werden. Die Standardaktion eines Signals kann nicht geändert werden. Sigkill Und Sigabrt Die Standardaktion des Signals kann nicht geändert oder ignoriert werden.

Signalhandhabung

Wenn ein Prozess ein Signal empfängt, hat der Prozess eine Maßnahme für diese Art von Signal. Der Prozess kann das Signal ignorieren, eine Handlerfunktion angeben oder die Standardaktion für diese Art von Signal akzeptieren.

  • Wenn die angegebene Aktion für das Signal ignoriert wird, wird das Signal sofort verworfen.
  • Das Programm kann eine Handlerfunktion mithilfe von Funktion wie z. B. registrieren Signal oder Sigaktion. Dies wird als Handler bezeichnet.
  • Wenn das Signal weder gehandhabt noch ignoriert wurde, findet seine Standardaktion statt.

Wir können das Signal verwenden Signal oder Sigaktion Funktion. Hier sehen wir, wie am einfachsten Signal() Funktion wird zum Umgang mit Signalen verwendet.

int signal () (int signum, void (*func) (int))

Der Signal() wird die nennen Func Funktion, wenn der Prozess ein Signal empfängt signalisieren. Der Signal() Gibt einen Zeiger zur Funktion zurück Func Wenn erfolgreich oder es einen Fehler an errno und -1 zurückgibt, sonst -1.

Der Func Zeiger kann drei Werte haben:

  1. Sig_dfl: Es ist ein Zeiger auf die Systemstandardfunktion Sig_dfl (), deklariert in H Header-Datei. Es wird verwendet, um die Standardaktion des Signals zu ergreifen.
  2. Sig_ign: Es ist ein Zeiger auf System ignorieren die Funktion Sig_ign (),deklariert in H Header-Datei.
  3. Benutzer definierter Handlerfunktion Zeiger: Der benutzerdefinierte Handler -Funktionstyp ist void (*) (int), bedeutet, dass der Rückgabetyp ungültig ist und ein Argument vom Typ int int.

Basic Signal Handler Beispiel

#enthalten
#enthalten
#enthalten
void sig_handler (int signum)
// Rückgabetyp der Handler -Funktion sollte ungültig sein
printf ("\ ninside Handler -Funktion \ n");

int main ()
Signal (SIGINT, SIG_Handler); // Signalhandler registrieren
für (int i = 1 ;; i ++) // Infinite Loop
printf ("%d: Innerhalb der Hauptfunktion \ n", i);
Schlaf (1); // Verzögerung für 1 Sekunde

Rückkehr 0;

Im Screenshot des Ausgangs von Beispiel11.C können wir sehen, dass in der Hauptfunktion die Infinite -Schleife ausführt. Wenn der Benutzer STRG+C eingetragen ist, wird die Ausführungsausführung der Hauptfunktion und die Funktion des Handlers des Signals aufgerufen. Nach Abschluss der Handlerfunktion wurde die Ausführung der Hauptfunktion wieder aufgenommen. Wenn Benutzertyp -Typisierte Strg+\, wird der Prozess beendet.

Signale ignorieren Beispiel

#enthalten
#enthalten
#enthalten
int main ()
Signal (SIGINT, SIG_IGN); // Signalhandler registrieren, um das Signal zu ignorieren
für (int i = 1 ;; i ++) // Infinite Loop
printf ("%d: Innerhalb der Hauptfunktion \ n", i);
Schlaf (1); // Verzögerung für 1 Sekunde

Rückkehr 0;

Hier wird die Handlerfunktion registriert zu registrieren Sig_ign () Funktion zum Ignorieren der Signalaktion. Also, wenn der Benutzer Strg+C eingegeben hat, Sigint Signal erzeugt, aber die Aktion wird ignoriert.

Wiederherstellungssignalbeispiel

#enthalten
#enthalten
#enthalten
void sig_handler (int signum)
printf ("\ ninside Handler -Funktion \ n");
Signal (SIGINT, SIG_DFL); // Registrieren Sie den Signalhandler für die Standardaktion

int main ()
Signal (SIGINT, SIG_Handler); // Signalhandler registrieren
für (int i = 1 ;; i ++) // Infinite Loop
printf ("%d: Innerhalb der Hauptfunktion \ n", i);
Schlaf (1); // Verzögerung für 1 Sekunde

Rückkehr 0;

Im Screenshot des Ausgangs von Beispiel33.c können wir sehen, dass beim ersten Tippen des Benutzers Strg+C die Handler -Funktion aufgerufen wird. In der Handler -Funktion registrieren sich der Signalhandler RE an Sig_dfl Für die Standardaktion des Signals. Wenn der Benutzer Strg+C zum zweiten Mal eingegeben hat, wird der Prozess beendet, was die Standardaktion von ist Sigint Signal.

Senden von Signalen:

Ein Prozess kann auch explizit Signale an sich selbst oder an einen anderen Prozess senden. Die Funktion raise () und Kill () kann zum Senden von Signalen verwendet werden. Beide Funktionen werden im Signal deklariert.H Header -Datei.

int erhöht (int signum)

Die Raise () -Funktion, die zum Senden von Signal verwendet wird signalisieren zum Anrufprozess (selbst). Es gibt Null zurück, wenn er erfolgreich ist, und ein Wert ungleich Null, wenn es fehlschlägt.

int Kill (pid_t pid, int signum)

Die zum Senden eines Signals verwendete Kill -Funktion signalisieren zu einer Prozess- oder Prozessgruppe, die von angegeben wird PID.

Sigusr1 -Signalhandlerbeispiel

#enthalten
#enthalten
void sig_handler (int signum)
printf ("Inside Handler -Funktion \ n");

int main ()
Signal (sigusr1, sig_handler); // Signalhandler registrieren
printf ("Inside Hauptfunktion \ n");
Erhöhung (sigusr1);
printf ("Inside Hauptfunktion \ n");
Rückkehr 0;

Hier sendet der Prozess das SIGUSR1 -Signal mit der Funktion RIX () an sich selbst an sich selbst.

Mit dem Kill -Beispielprogramm erhöhen

#enthalten
#enthalten
#enthalten
void sig_handler (int signum)
printf ("Inside Handler -Funktion \ n");

int main ()
PID_T PID;
Signal (sigusr1, sig_handler); // Signalhandler registrieren
printf ("Inside Hauptfunktion \ n");
pid = getPid (); // Verarbeitungs -ID von sich selbst
töten (pid, sigusr1); // Sigusr1 an sich selbst senden
printf ("Inside Hauptfunktion \ n");
Rückkehr 0;

Hier senden der Prozess Sigusr1 Signal für sich selbst mit töten() Funktion. getPid () wird verwendet, um die Prozess -ID von sich selbst zu erhalten.

Im nächsten Beispiel werden wir sehen, wie Eltern- und Kinderprozesse kommuniziert (Inter -Process -Kommunikation) mithilfe töten() und Signalfunktion.

Elternkind Kommunikation mit Signalen

#enthalten
#enthalten
#enthalten
#enthalten
void sig_handler_parent (int signum)
printf ("übergeordnet: erhalten ein Antwortsignal von Child \ n");

void sig_handler_child (int signum)
printf ("Kind: erhalten ein Signal von übergeordnetem \ n");
Schlaf (1);
Kill (getppid (), Sigusr1);

int main ()
PID_T PID;
if ((pid = fork ())<0)
printf ("gabel fehlgeschlagen \ n");
Ausgang (1);

/ * Kinderprozess */
sonst if (pid == 0)
Signal (sigusr1, sig_handler_child); // Signalhandler registrieren
printf ("Kind: Warten auf Signal \ n");
Pause();

/ * Elternprozess */
anders
Signal (sigusr1, sig_handler_parent); // Signalhandler registrieren
Schlaf (1);
printf ("übergeordnet: Signal an Child \ n");
töten (pid, sigusr1);
printf ("Eltern: Warten auf Antwort \ n");
Pause();

Rückkehr 0;

Hier, Gabel() Die Funktion erstellt Kinderprozess und gibt Null an den Kinderprozess und die Kinderprozess -ID in den übergeordneten Prozess zurück. PID wurde also überprüft, um über Eltern- und Kinderprozess zu entscheiden. Im übergeordneten Prozess wird es 1 Sekunde lang geschliffen, damit ein untergeordneter Prozess die Signalhandlerfunktion registrieren und auf das Signal von Eltern warten kann. Nach 1 zweiten übergeordneten Prozess senden Sigusr1 Signal auf den Kinderprozess und warten Sie auf das Reaktionssignal des Kindes. Im untergeordneten Prozess wartet es zunächst auf das Signal von Eltern und wenn das Signal empfangen wird, wird die Handler -Funktion aufgerufen. Aus der Handler -Funktion sendet der untergeordnete Prozess einen anderen Sigusr1 Signal an Eltern. Hier Getppid () Die Funktion wird zum Abrufen der übergeordneten Prozess -ID verwendet.

Abschluss

Signal in Linux ist ein großes Thema. In diesem Artikel haben wir gesehen.