1. Signalliste
Die häufigsten sind:
1.1. Echtzeitsignal und Nicht-EchtzeitsignalWie oben listet kill alle Signale auf. Echtzeitsignale und Nicht-Echtzeitsignale werden auch als zuverlässige Signale und unzuverlässige Signale bezeichnet. SIGRTMIN und die Signale danach sind Echtzeitsignale, und die Signale davor sind Nicht-Echtzeitsignale. Der Unterschied besteht darin, dass Echtzeitsignale wiederholte Warteschlangen unterstützen, Nicht-Echtzeitsignale jedoch nicht. Standardmäßig werden Signale, die nicht in Echtzeit erfolgen, nur einmal in der Warteschlange angezeigt. Dies bedeutet, dass selbst wenn sie mehrmals gesendet werden, am Ende nur eines empfangen wird. Es gibt auch einen Unterschied in der Reihenfolge des Herausnehmens aus der Warteschlange, d. h. das erste herausgenommene Signal muss ein Echtzeitsignal sein. PS:
1.2 SignalstatusDer Zustand „anstehend“ eines Signals bezeichnet die Zeitspanne von der Erzeugung des Signals bis zu dessen Verarbeitung, die „Sperrung“ eines Signals ist eine Schalthandlung, die bedeutet, dass die Verarbeitung des Signals verhindert wird, nicht jedoch die Erzeugung des Signals. Beispielsweise wird vor dem Schlafengehen sigprocmask verwendet, um das Austrittssignal zu blockieren, dann wird der Schlaf ausgeführt und dann wird während des Schlafvorgangs ein Austrittssignal generiert. Zu diesem Zeitpunkt wurde das Austrittssignal jedoch blockiert (das chinesische Wort „blockieren“ wird leicht als Zustand missverstanden. Tatsächlich ist es eine Aktion ähnlich einem Schalter, daher wird „blockiert“ statt „blockiert“ gesagt), sodass es sich im Zustand „ausstehend“ befindet. Nach dem Schlafengehen wird sigprocmask verwendet, um den blockierenden Schalter des Austrittssignals auszuschalten. Da sich das zuvor generierte Austrittssignal im ausstehenden Zustand befunden hat, verlässt es beim Ausschalten des blockierenden Schalters sofort den Zustand „ausstehend“ und wird verarbeitet. All dies geschieht, bevor sigprocmask zurückkehrt. 1.3 SignallebenszyklusDer vollständige Lebenszyklus eines Signals (vom Senden des Signals bis zum Abschluss der entsprechenden Verarbeitungsfunktion) kann in drei wichtige Phasen unterteilt werden, die durch vier wichtige Ereignisse gekennzeichnet sind: 1. Signal ist geboren; 2. Dabei wird das Signal registriert; 3. Dabei wird das Signal abgemeldet; 4. Die Signalverarbeitungsfunktion wird ausgeführt. Das Zeitintervall zwischen zwei benachbarten Ereignissen stellt eine Phase im Signallebenszyklus dar. Nachfolgend wird die praktische Bedeutung der vier Ereignisse erläutert:
Struktursignierung ausstehend; Struktursignatur { Struktur sigqueue *Kopf, **Ende; sigset_t-Signal; }; Die Signalregistrierung in einem Prozess bedeutet, dass der Signalwert zum ausstehenden Signalsatz des Prozesses (dem zweiten Mitglied der Sigpending-Struktur, dem Signal sigset_t) hinzugefügt wird und die vom Signal übertragenen Informationen in einer Sigqueue-Struktur in der ausstehenden Signalinformationskette beibehalten werden. Solange sich das Signal im ausstehenden Signalsatz des Prozesses befindet, bedeutet dies, dass der Prozess sich der Existenz dieser Signale bewusst ist, aber keine Zeit hatte, sie zu verarbeiten, oder dass das Signal vom Prozess blockiert wird. 1. Dabei wird das Signal abgemeldet. Während der Ausführung des Zielprozesses wird geprüft, ob Signale auf die Verarbeitung warten (diese Prüfung wird bei jeder Rückkehr vom Systembereich in den Benutzerbereich durchgeführt). Wenn ein ausstehendes Signal auf die Verarbeitung wartet und das Signal nicht durch den Prozess blockiert wird, entfernt der Prozess die vom Signal belegte Struktur in der ausstehenden Signalkette, bevor die entsprechende Signalverarbeitungsfunktion ausgeführt wird. Ob ein Signal aus dem ausstehenden Signalsatz des Prozesses entfernt wird, ist für Echtzeit- und Nicht-Echtzeit-Signale unterschiedlich. Bei Nicht-Echtzeitsignalen gilt: Da sie höchstens eine Sigqueue-Struktur in der ausstehenden Signalinformationskette belegen, sollte das Signal aus dem ausstehenden Signalsatz des Prozesses gelöscht werden, nachdem die Struktur freigegeben wurde (die Signallöschung ist abgeschlossen). Bei Echtzeitsignalen können sie mehrere Sigqueue-Strukturen in der ausstehenden Signalinformationskette belegen, daher sollten sie je nach Anzahl der belegten Gqueue-Strukturen unterschiedlich behandelt werden: Wenn nur eine Sigqueue-Struktur belegt ist (der Prozess empfängt das Signal nur einmal), sollte das Signal aus dem ausstehenden Signalsatz des Prozesses gelöscht werden (die Signallöschung ist abgeschlossen). Andernfalls wird das Signal nicht aus dem schwebenden Signalsatz des Prozesses entfernt (Signallöschung ist abgeschlossen). Bevor ein Prozess die entsprechende Signalverarbeitungsfunktion ausführt, muss er zunächst das Signal im Prozess abmelden. 2. Signallebensdauer endet. Nachdem der Prozess das Signal gelöscht hat, wird die entsprechende Signalverarbeitungsfunktion sofort ausgeführt. Nach Abschluss der Ausführung wird der Einfluss des diesmal gesendeten Signals auf den Prozess vollständig beendet. 1.4. Ausführung und Aufhebung von SignalenDer Kernel verarbeitet das von einem Prozess empfangene Soft-Interrupt-Signal im Kontext des Prozesses, daher muss sich der Prozess im laufenden Zustand befinden. Wenn es die CPU wiedererlangt, weil es durch ein Signal oder eine normale Planung aufgeweckt wurde, erkennt es, ob bei der Rückkehr vom Kernelbereich in den Benutzerbereich ein Signal auf die Verarbeitung wartet. Wenn ein ausstehendes Signal auf die Verarbeitung wartet und das Signal nicht durch den Prozess blockiert wird, entfernt der Prozess die vom Signal belegte Struktur in der ausstehenden Signalkette, bevor die entsprechende Signalverarbeitungsfunktion ausgeführt wird. Wenn alle nicht maskierten Signale verarbeitet wurden, kann die Rückkehr in den Benutzerbereich erfolgen. Bei einem maskierten Signal wird nach Entfernen der Maske der oben beschriebene Prüf- und Verarbeitungsablauf bei der Rückkehr in den Benutzerbereich erneut ausgeführt. Es gibt drei Arten der Signalverarbeitung: Der Prozess wird nach Empfang des Signals beendet. Der Prozess ignoriert das Signal. Der Prozess führt nach Empfang des Signals die vom Benutzer mithilfe des Systemaufrufsignals festgelegte Funktion aus. Wenn ein Prozess ein Signal empfängt, das er ignoriert, verwirft der Prozess das Signal und wird weiter ausgeführt, als hätte er das Signal nicht empfangen. Wenn der Prozess ein abzufangendes Signal empfängt, wird die benutzerdefinierte Funktion ausgeführt, wenn der Prozess vom Kernelmodus in den Benutzermodus zurückkehrt. Darüber hinaus ist die Methode zum Ausführen benutzerdefinierter Funktionen sehr clever. Der Kernel erstellt eine neue Ebene auf dem Benutzerstapel, in der der Wert der Rücksprungadresse auf die Adresse der benutzerdefinierten Verarbeitungsfunktion gesetzt wird. Auf diese Weise kehrt der Prozess, wenn er vom Kernel zurückkehrt und den oberen Teil des Stapels abhebt, zur benutzerdefinierten Funktion zurück. Wenn er von der Funktion zurückkehrt und den oberen Teil des Stapels erneut abhebt, kehrt er an die Stelle zurück, an der er ursprünglich in den Kernel eingetreten ist. Der Grund hierfür liegt darin, dass benutzerdefinierte Verarbeitungsfunktionen nicht im Kernelmodus ausgeführt werden können und dürfen (wenn benutzerdefinierte Funktionen im Kernelmodus ausgeführt werden, kann der Benutzer beliebige Berechtigungen erhalten). Zum Beispiel: #include <assert.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> void meinHandler(int num) { int ret = 0; wenn (SIGUSR1 == num) { sigset_t gesetzt; ret = sigempyset(&set); : Assert(!(-1 == ret)); ret = sigaddset(&set, SIGINT); : Assert(!(-1 == ret)); ret = sigaddset(&set, SIGRTMIN); : Assert(!(-1 == ret)); ret = sigprocmask(SIG_UNBLOCK, &set, NULL); : Assert(!(-1 == ret)); printf("Entsperren der Empfangssignaturnummer: %d\n", num); } sonst wenn (num == SIGINT || num == SIGRTMIN) { printf("empfangene Signaturnummer: %d\n", Nummer); } anders { printf("Anderes Signal, Empfangssignaturnummer: %d\n", num); } } int Haupt(void) { pid_t pid; int ret = 0; //Rückruffunktion festlegen struct sigaction act; act.sa_handler = meinHandler; act.sa_flags = SA_SIGINFO; //Registriere die Verarbeitungsfunktion des Nicht-Echtzeit-Signals ret = sigaction(SIGINT, &act, NULL); : Assert(!(-1 == ret)); // Registrieren Sie die Echtzeit-Signalverarbeitungsfunktion ret = sigaction(SIGRTMIN, &act, NULL); : Assert(!(-1 == ret)); // Benutzerdefiniertes Signal registrieren ret = sigaction(SIGUSR1, &act, NULL); : Assert(!(-1 == ret)); // SIGINT SIGRTMIN zum blockierenden Statuswort sigset_t set hinzufügen; ret = sigempyset(&set); : Assert(!(-1 == ret)); ret = sigaddset(&set, SIGINT); : Assert(!(-1 == ret)); ret = sigaddset(&set, SIGRTMIN); : Assert(!(-1 == ret)); ret = sigprocmask(SIG_BLOCK, &set, NULL); : Assert(!(-1 == ret)); pid = gabel(); : Assert(!(-1 == ret)); wenn (0 == pid) { Vereinigungssignalwert; Wert.sival_int = 10; } // Sende drei instabile Signale für (i = 0; i < 3; i++) { ret = sigqueue(getppid(), SIGINT, Wert); : Assert(!(-1 == ret)); printf("Senden eines unzuverlässigen Signals ok\n"); } //Sende drei stabile Signale value.sival_int = 20; für (i = 0; i < 3; i++) { ret = sigqueue(getppid(), SIGRTMIN, Wert); : Assert(!(-1 == ret)); printf("Sende zuverlässiges Signal ok\n"); } //Senden Sie SIGUSR1 an den übergeordneten Prozess, um die Blockierung aufzuheben. ret = kill(getppid(), SIGUSR1); : Assert(!(-1 == ret)); } während (1) { Schlaf (1); } gebe 0 zurück; } 2. Vererbung von Signalmasken und Signalverarbeitungsfunktionen2.1. Vererbung von SignalverarbeitungsfunktionenDie Signalverarbeitungsfunktion ist ein Prozessattribut, daher ist die Signalverarbeitungsfunktion jedes Threads im Prozess dieselbe. Der durch Fork erstellte untergeordnete Prozess erbt die Signalverarbeitungsfunktion des übergeordneten Prozesses. Nach der Ausführung wird die zu verarbeitende Signalverarbeitungsfunktion auf die Standardfunktion zurückgesetzt und die zu ignorierenden Signale bleiben unverändert. Dies bedeutet, dass, wenn die Signaleinstellung im übergeordneten Prozess SIG_IGN lautet, die Verarbeitung dieses Signals bei der Ausführung des untergeordneten Prozesses weiterhin ignoriert und nicht auf die Standardfunktion zurückgesetzt wird. Zum Beispiel: // test.c --> Test #include <stdlib.h> Typdefinition void (*sighandler_t)(int); statischer signhandler_t alter_int_handler; statischer sighandler_t alte_handler[SIGSYS + 1]; void sig_handler(int signo) { printf("Signo empfangen %d\n",Signo); alte_handler[zeichen](zeichen); } int main(int argc, char **argv) { alte_handler[SIGINT] = signal(SIGINT, SIG_IGN); alte_handler[SIGTERM] = signal(SIGTERM, sig_handler); int ret; ret = Gabel(); wenn (ret == 0) { //Kind // Hier führt execlp test2 als untergeordneten Prozess aus. execlp("/tmp/test2", "/tmp/test2",(char*)NULL); }sonst wenn (ret > 0) { //Elternteil während(1) { Schlaf (1); } }anders{ perror(""); abbrechen(); } } ================================================ test2.c --> test2 #include <stdio.h> int main(int argc, char **argv) { während(1) { Schlaf (1); } gebe 0 zurück; } Fazit: Nachdem der Test auf Test2 geändert wurde, wird SIGINT weiterhin ignoriert und SIGTERM auf den Standardmodus zurückgesetzt. 2.2 SignalmaskenvererbungFür die Signalmaske gelten die folgenden Regeln: 1. Jeder Thread kann seine eigene Signalmaske haben. 2. Der gegabelte untergeordnete Prozess erbt die Signalmaske des übergeordneten Prozesses und die Signalmaske bleibt nach der Ausführung unverändert. Wenn der übergeordnete Prozess mehrere Threads umfasst, erbt der untergeordnete Prozess nur die Maske des Hauptthreads. 3. Das an den Prozess gesendete Signal wird von jedem Thread empfangen, der das Signal nicht blockiert. Beachten Sie, dass nur ein Thread es zufällig empfängt. Wenn unter Linux alle Threads Signale empfangen können, wird das Signal standardmäßig an den Hauptthread gesendet, während es im POSIX-System zufällig gesendet wird. 4. Nach dem Fork wird der ausstehende Signalsatz im untergeordneten Prozess initialisiert und leer gelassen, und exec behält den ausstehenden Signalsatz bei. #include <stdio.h> #include <signal.h> #include <unistd.h> #include <stdlib.h> #include <pthread.h> Typdefinition void (*sighandler_t)(int); statischer void *thread1(void *arg) { sigset_t gesetzt; printf("im Thread1\n"); sigempyset(&set); sigaddset(&set, SIGTERM); pthread_sigmask(SIG_BLOCK, &set, NULL); während(1) { Schlaf (1); } } statisches void sigset_print(sigset_t *set) { int ich; für (i = 1; i <= SIGSYS; i++) { wenn (sigismember(set, i)) { printf("Signal %d ist im Set\n",i); } } } int main(int argc, char **argv) { int ret; sigset_t gesetzt; pthread_t pid; pthread_create(&pid, NULL, thread1, NULL); Schlaf (1); sigempyset(&set); sigaddset(&set, SIGINT); pthread_sigmask(SIG_BLOCK, &set, NULL); ret = Gabel(); wenn (ret == 0) { //Kind pthread_sigmask(SIG_BLOCK, NULL, &set); sigset_print(&set); während(1) { Schlaf (1); } }sonst wenn (ret > 0) { //Elternteil während(1) { Schlaf (1); } }anders{ perror(""); abbrechen(); } } Fazit: Nur die im Hauptthread festgelegte Maske wird an den Kindprozess vererbt. Der Grund dafür ist, dass Fork unter Linux nur den Thread kopiert, der fork() aufruft. Im untergeordneten Prozess wird also nur der Hauptthread des übergeordneten Prozesses kopiert, und natürlich ist die Signalmaske eine Kopie der Signalmaske des Hauptthreads des übergeordneten Prozesses. Dies beweist erneut, dass, wenn Fork in Thread1 aufgerufen wird, die Signalmaske des untergeordneten Prozesses eine Kopie von Thread1 ist. 2.3, Sigwait und MultithreadingSigwait-Funktion: Sigwait wartet auf das Auftreten eines oder mehrerer angegebener Signale. Es bewirkt nur zwei Dinge: Achten Sie zunächst auf blockierte Signale. Zweitens: Wenn das überwachte Signal generiert wird, wird es aus der Warteschlange entfernt. sigwait ändert den blockierenden oder nicht blockierenden Status der Signalmaske nicht. Wenn ein Prozess im POSIX-Standard ein Signal empfängt und es sich um eine Multithread-Situation handelt, können wir nicht feststellen, welcher Thread das Signal verarbeitet. Sigwait entnimmt im Prozess den ausstehenden Signalen das angegebene Signal. Wenn Sie in diesem Fall sicherstellen möchten, dass der Sigwait-Thread das Signal empfängt, müssen alle Threads, einschließlich des Hauptthreads und des Sigwait-Threads, das Signal blockieren, denn wenn Sie sich nicht selbst blockieren, gibt es kein Signal im ausstehenden Zustand (blockierter Zustand). Wenn alle anderen Threads nicht blockieren, ist es möglich, dass das Signal, wenn es eintrifft, von anderen Threads verarbeitet wird. PS: Verwenden Sie in Multithread-Code immer Funktionen wie sigwait, sigwaitinfo oder sigtimedwait, um Signale zu verarbeiten. Anstelle von Funktionen wie Signal oder Sigaction. Denn das Aufrufen von Funktionen wie Signal oder Sigaction in einem Thread ändert die Signalverarbeitungsfunktionen in allen Threads, anstatt nur die Signalverarbeitungsfunktion des Threads zu ändern, der Signal/Sigaction aufruft. 2.4. Signale in mehreren ProzessenIm Multiprozessmodus werden durch die Tastatur ausgelöste Signale gleichzeitig an alle Prozesse in der aktuellen Prozessgruppe gesendet. Wenn ein Programm während der Ausführung mehrere Kindprozesse aufspaltet, wird das durch die Taste ausgelöste Signal von allen Prozessen des Programms empfangen. Im Gegensatz zum Multithreading sind die Signalmasken und Signalverarbeitungsfunktionen beim Multiprozess jedoch unabhängig. Jeder Prozess kann wählen, ob er die Verarbeitung durchführen möchte oder nicht, und kann auch seine eigene Signalmaske festlegen. #include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <signal.h> int main(int argc, char **argv) { pid_t pid = gabel(); Signal (SIGCHLD, SIG_IGN); wenn (pid < 0) printf("Fehler Fork\n"); sonst wenn (pid == 0) { signal(SIGINT, SIG_IGN); // SIGINT ignorieren, damit der Kindprozess nach Strg+C überleben kann; wenn nicht festgelegt, wird er beim Empfang des Signals beendet printf("child gid = %ld\n", getpgid(getpid())); Tun { Schlaf (1); } während (1); } anders { printf("übergeordnete gid = %ld\n", getpgid(getpid())); Tun { Schlaf (1); } während (1); } gebe 0 zurück; } Wie in der obigen Abbildung dargestellt, können Sie sehen, dass der übergeordnete Prozess nach dem Empfang von SIGINT beendet wird und der untergeordnete Prozess nicht betroffen ist, da er so eingestellt ist, dass er SIGINT ignoriert. APIs3.1 Signalerzeugungsfunktion1.kill(pid_t pid, int signum); 2. int sigqueue(pid_t pid, int sig, const union sigval-Wert); 3.pthread_kill(pthread_t tid, int signum); 4.raise(int signum); // Sende dir selbst ein Signal 5. Alarm löschen (leer); 6.void abbrechen(void); 7.int setitimer(int which, const struct itimerval *neuer_Wert, struct itimerval *alter_Wert); PS: sigqueue() übergibt mehr zusätzliche Informationen als kill(), aber sigqueue() kann Signale nur an einen Prozess senden, nicht an eine Prozessgruppe. Wenn signo=0 ist, wird eine Fehlerprüfung durchgeführt, aber es wird kein Signal gesendet. Das Signal mit dem Wert 0 kann verwendet werden, um die Gültigkeit von pid zu prüfen und um festzustellen, ob der aktuelle Prozess die Berechtigung hat, Signale an den Zielprozess zu senden. 3.2 Signalverarbeitungsfunktion1.Signal(int signum, void (*handler)(int signum)) 2.sigaction(int signum, Struktur sigaction*neueAktion, sigaction*alteAktion) Unterzeichnungsakt; act.sa_handler = Handler; act.sa_flags = SA_SIGINFO; //Signalverarbeitungsfunktion registrieren sigaction(SIGINT, act, NULL); 3.3 Signalmaskenfunktion1.sigprocmask(int wie, Struktur sigaction* gesetzt, Struktur sigaction* altes Set) 2.pthread_sigmask(int wie, Struktur sigaction* gesetzt, Struktur sigaction* altes Set) sigprocmask wird verwendet, um die Signalmaske des Prozesses festzulegen, und pthread_sigmask wird verwendet, um die Signalmaske des Threads festzulegen. Die Parameter der beiden sind gleich. Der erste Parameter hat 3.4. Signalerfassungsvariablen
3.5. Signalabschirmfunktion1.int sigpending(sigset_t *set); // Gibt das blockierte Signalset zurück 2.int sigsuspend(const sigset_t *mask); sigsuspend bedeutet, die Signalmaske vorübergehend auf mask zu setzen und den Prozess anzuhalten, bis ein Signal generiert wird (nicht maskierte Signale können den Prozess aufwecken oder beenden). Wenn die Signalverarbeitungsfunktion zurückkehrt, stellt siguspend die vorherige Signalmaske wieder her (vorübergehend). Angenommen, das Signal A wird generiert, wenn Sisuspend den Prozess blockiert, und A ist kein maskiertes Signal in der Maske. Dann gibt es zwei Situationen für die Signalverarbeitungsfunktion von A. 1: Beenden Sie den Prozess direkt. Zu diesem Zeitpunkt existiert der Prozess nicht mehr, sodass sigsuspend nicht zurückkehren muss (wenn es keinen Prozess gibt, existiert auch sigsuspend nicht, ebenso wie der Funktionsstapel); 2. Wenn die Verarbeitungsfunktion des Signals A zurückkehrt, wird das Signalmaskenwort in den Zustand vor Sigsuspend zurückversetzt (das Signalmaskenwort wird beim Aufruf von Sigsuspend auf „Maske“ gesetzt und muss daher in den Zustand vor dem Aufruf von Sigsuspend zurückversetzt werden). Anschließend gibt Sigsuspend -1 zurück und setzt den Fehler auf EINTR. Oben wird kurz auf die Einzelheiten des Linux-Signalmechanismus eingegangen. Weitere Informationen zum Linux-Signalmechanismus finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM! Das könnte Sie auch interessieren:
|
>>: Das Textdesign einer Webseite sollte aussehen wie die Kleidung von intelligenten Mädchen
CSS stimmt mit mehreren Klassen überein Das folge...
1. Entwicklungsumgebung vue+vant 2. Computersyste...
Zuerst müssen Sie Navicat für MySQL herunterladen...
1. Erstellen Sie eine Testtabelle Tabelle `mysql_...
Bei der Entwicklung eines Backend-Verwaltungsproj...
Tipps zum Anzeigen von Verlaufsdatensätzen und Hi...
1. Objektorientierte Klassenvererbung In den obig...
Es ist nicht einfach, die vertikale Zentrierung vo...
Inhaltsverzeichnis Vorwort 1. Was sind Mixins? 2....
Primärschlüssel: Schlagwort: Primärschlüssel Funk...
Vorwort: Heute möchte ich mich per Remote-Zugriff...
Inhaltsverzeichnis Überblick Hash-Eigenschaften G...
Inhaltsverzeichnis Zwei Module zur Verwendung von...
Inhaltsverzeichnis 1. Primärschlüssel vorhanden 2...
Verwandte Artikel: Anfänger lernen einige HTML-Ta...