Heim  >  Artikel  >  System-Tutorial  >  Signalmechanismus unter Linux: Verwendung von Signalen für die Kommunikation und Steuerung zwischen Prozessen

Signalmechanismus unter Linux: Verwendung von Signalen für die Kommunikation und Steuerung zwischen Prozessen

WBOY
WBOYnach vorne
2024-02-12 12:40:031174Durchsuche

Linux 下的信号机制:如何使用信号进行进程间通信和控制

Signal ist eine häufig verwendete prozessübergreifende Kommunikations- und Steuerungsmethode in Linux-Systemen. Sie ermöglicht es einem Prozess, eine einfache Nachricht an einen anderen Prozess zu senden, um ihn darüber zu informieren, dass ein bestimmtes Ereignis oder ein bestimmter Status aufgetreten ist. Die Funktion von Signalen besteht darin, die Reaktionsfähigkeit und Flexibilität des Systems zu verbessern, um mit einigen Ausnahme- oder Notfallsituationen umzugehen. Im Linux-System gibt es viele Arten von Signalen wie SIGINT, SIGTERM, SIGKILL usw. Jedes davon hat seine eigene Bedeutung und Funktion und eignet sich für unterschiedliche Szenarien und Anforderungen. Aber verstehen Sie den Signalmechanismus unter Linux wirklich? Wissen Sie, wie man Signale für die Kommunikation und Steuerung zwischen Prozessen unter Linux nutzt? Wissen Sie, wie man unter Linux mit Signalen umgeht und diese ignoriert? In diesem Artikel werden Ihnen die relevanten Kenntnisse des Signalmechanismus unter Linux im Detail vorgestellt, sodass Sie diese leistungsstarke prozessübergreifende Kommunikations- und Steuerungsmethode unter Linux besser nutzen und verstehen können.

1. Grundkonzepte von Signalen

In diesem Abschnitt werden zunächst einige grundlegende Konzepte von Signalen vorgestellt und anschließend einige grundlegende Signaltypen und Ereignisse aufgeführt, die den Signalen entsprechen. Grundlegende Konzepte sind besonders wichtig für das Verständnis und die Nutzung von Signalen sowie für das Verständnis von Signalmechanismen. Werfen wir einen Blick darauf, was ein Signal ist.

1. Grundkonzepte

Soft-Interrupt-Signal (Signal, auch als Signal bezeichnet) wird verwendet, um den Prozess darüber zu informieren, dass ein asynchrones Ereignis aufgetreten ist. Prozesse können über den Systemaufruf kill untereinander Soft-Interrupt-Signale senden. Der Kernel kann aufgrund interner Ereignisse auch Signale an den Prozess senden und den Prozess darüber informieren, dass ein Ereignis aufgetreten ist. Beachten Sie, dass Signale nur dazu verwendet werden, einen Prozess darüber zu informieren, welche Ereignisse eingetreten sind, und keine Daten an den Prozess weitergeben.

Der Prozess, der das Signal empfängt, verfügt über unterschiedliche Verarbeitungsmethoden für verschiedene Signale. Die Verarbeitungsmethoden können in drei Kategorien unterteilt werden: Die erste ist ein Interrupt-ähnlicher Handler. Für das zu verarbeitende Signal kann der Prozess eine Verarbeitungsfunktion angeben, die es verarbeitet. Die zweite Methode besteht darin, ein Signal zu ignorieren und nichts mit dem Signal zu tun, als ob es nie passiert wäre. Die dritte Methode besteht darin, den Standardwert des Systems für die Verarbeitung des Signals beizubehalten. Bei dieser Standardoperation besteht die Standardoperation für die meisten Signale darin, den Prozess zu beenden. Der Prozess verwendet das Systemaufrufsignal, um das Verarbeitungsverhalten des Prozesses für ein bestimmtes Signal anzugeben.

Im Eintrag der Prozesstabelle gibt es ein Soft-Interrupt-Signalfeld. Jedes Bit in diesem Feld entspricht einem Signal. Wenn ein Signal an den Prozess gesendet wird, wird das entsprechende Bit gesetzt. Daraus ist ersichtlich, dass der Prozess verschiedene Signale gleichzeitig speichern kann, der Prozess jedoch vor der Verarbeitung nicht weiß, wie viele Signale für dasselbe Signal eingegangen sind.

2. Signaltyp

Es gibt viele Gründe für das Senden von Signalen, um verschiedene Signale zu verstehen:

(1) Signale im Zusammenhang mit der Prozessbeendigung. Diese Art von Signal wird ausgegeben, wenn der Prozess beendet wird oder der untergeordnete Prozess beendet wird.
(2) Signale im Zusammenhang mit Prozessausnahmeereignissen. Beispielsweise überschreitet der Prozess die Grenze oder versucht, in einen schreibgeschützten Speicherbereich (z. B. den Programmtextbereich) zu schreiben oder führt eine privilegierte Anweisung aus und es treten verschiedene andere Hardwarefehler auf.
(3) Signale im Zusammenhang mit dem Auftreten nicht behebbarer Zustände während Systemaufrufen. Beispielsweise wurden beim Ausführen des Systemaufrufs exec die ursprünglichen Ressourcen freigegeben und die aktuellen Systemressourcen erschöpft.
(4) Signale im Zusammenhang mit dem Auftreten nicht vorhersehbarer Fehlerbedingungen beim Ausführen von Systemaufrufen. Zum Beispiel das Ausführen eines Systemaufrufs, der nicht existiert.
(5) Von Prozessen im Benutzermodus gesendete Signale. Beispielsweise ruft ein Prozess den Systemaufruf kill auf, um Signale an andere Prozesse zu senden.
(6) Signale im Zusammenhang mit der Terminalinteraktion. Beispielsweise schließt der Benutzer ein Terminal oder drückt die Pause-Taste.
(7) Verfolgen Sie die Signale der Prozessausführung.

Die Liste der von Linux unterstützten Signale lautet wie folgt. Viele Signale hängen mit der Architektur der Maschine zusammen. Die ersten aufgeführten sind die in POSIX.1 aufgeführten Signale:

Signalwert Verarbeitungsaktion Grund für das Senden des Signals
——————————————————————-

SIGHUP 1 A 终端挂起或者控制进程终止 
SIGINT 2 A 键盘中断(如break键被按下) 
SIGQUIT 3 C 键盘的退出键被按下 
SIGILL 4 C 非法指令 
SIGABRT 6 C 由abort(3)发出的退出指令 
SIGFPE 8 C 浮点异常 
SIGKILL 9 AEF Kill信号 
SIGSEGV 11 C 无效的内存引用 
SIGPIPE 13 A 管道破裂: 写一个没有读端口的管道 
SIGALRM 14 A 由alarm(2)发出的信号 
SIGTERM 15 A 终止信号 
SIGUSR1 30,10,16 A 用户自定义信号1 
SIGUSR2 31,12,17 A 用户自定义信号2 
SIGCHLD 20,17,18 B 子进程结束信号 
SIGCONT 19,18,25 进程继续(曾被停止的进程) 
SIGSTOP 17,19,23 DEF 终止进程 
SIGTSTP 18,20,24 D 控制终端(tty)上按下停止键 
SIGTTIN 21,21,26 D 后台进程企图从控制终端读 
SIGTTOU 22,22,27 D 后台进程企图从控制终端写 

Die folgenden Signale sind nicht in POSIX.1 aufgeführt, sondern in SUSv2

Signalwert Verarbeitungsaktion Grund für das Senden des Signals
——————————————————————–

SIGBUS 10,7,10 C 总线错误(错误的内存访问) 
SIGPOLL A Sys V定义的Pollable事件,与SIGIO同义 
SIGPROF 27,27,29 A Profiling定时器到 
SIGSYS 12,-,12 C 无效的系统调用 (SVID) 
SIGTRAP 5 C 跟踪/断点捕获 
SIGURG 16,23,21 B Socket出现紧急条件(4.2 BSD) 
SIGVTALRM 26,26,28 A 实际时间报警时钟信号(4.2 BSD) 
SIGXCPU 24,24,30 C 超出设定的CPU时间限制(4.2 BSD) 
SIGXFSZ 25,25,31 C 超出设定的文件大小限制(4.2 BSD) 

(对于SIGSYS,SIGXCPU,SIGXFSZ,以及某些机器体系结构下的SIGBUS,Linux缺省的动作是A (terminate),SUSv2 是C (terminate and dump core))。 

Hier sind einige andere Signale

Signalwert Verarbeitungsaktion Grund für das Senden des Signals
——————————————————————-

SIGIOT 6 C IO捕获指令,与SIGABRT同义 
SIGEMT 7,-,7 
SIGSTKFLT -,16,- A 协处理器堆栈错误 
SIGIO 23,29,22 A 某I/O操作现在可以进行了(4.2 BSD) 
SIGCLD -,-,18 A 与SIGCHLD同义 
SIGPWR 29,30,19 A 电源故障(System V) 
SIGINFO 29,-,- A 与SIGPWR同义 
SIGLOST -,-,- A 文件锁丢失 
SIGWINCH 28,28,20 B 窗口大小改变(4.3 BSD, Sun) 
SIGUNUSED -,31,- A 未使用的信号(will be SIGSYS) 

(Hier bedeutet -, dass das Signal nicht implementiert ist; es gibt drei Werte mit gegebener Bedeutung, der erste Wert ist normalerweise für Alpha und Sparc gültig, der mittlere Wert entspricht i386 und ppc und sh und der letzte Wert entspricht Mips. Signal 29 SIGINFO/SIGPWR auf Alpha, SIGLOST auf Sparc)

Die Bedeutung der Buchstaben im Verarbeitungsaktionselement ist wie folgt
A Die Standardaktion besteht darin, den Prozess zu beenden
B Die Standardaktion besteht darin, dieses Signal zu ignorieren
Die Standardaktion von C besteht darin, den Prozess zu beenden und einen Kernel-Image-Dump (Dump Core) durchzuführen
D Die Standardaktion besteht darin, den Prozess zu stoppen
E-Signal kann nicht erfasst werden
Das F-Signal kann nicht ignoriert werden

Die oben vorgestellten Signale werden von gängigen Systemen unterstützt. Die Namen, Funktionen und Verarbeitungsaktionen verschiedener Signale werden standardmäßig in Tabellenform vorgestellt. Die Bedeutung verschiedener Standardverarbeitungsaktionen ist: Das Beenden des Programms bedeutet, dass der Prozess beendet wird. Das Ignorieren des Signals bedeutet, dass das Signal verworfen wird, ohne es zu verarbeiten. Das bedeutet, dass das Programm hängen bleibt und nach dem Eintritt in den gestoppten Zustand neu gestartet werden kann Debuggen (z. B. Ptrace-Systemaufruf); Kernel-Image-Dump bezieht sich auf das Ablegen des Abbilds der Prozessdaten im Speicher und eines Teils des in der Kernelstruktur des Prozesses gespeicherten Inhalts in einem bestimmten Format in das Dateisystem, und der Prozess beendet die Ausführung. Auf diese Weise Der Vorteil besteht darin, dass Programmierer bequem Datenwerte erhalten können, während der Prozess ausgeführt wird, sodass sie die Ursache des Speicherauszugs ermitteln und ihre Programme debuggen können.

Beachten Sie, dass die Signale SIGKILL und SIGSTOP weder abgefangen noch ignoriert werden können. Die Signale SIGIOT und SIGABRT sind ein Signal. Es ist ersichtlich, dass dasselbe Signal in verschiedenen Systemen unterschiedliche Werte haben kann. Daher wird empfohlen, den für das Signal definierten Namen zu verwenden, anstatt den Wert des Signals direkt zu verwenden.

2. Signalmechanismus

Das Grundkonzept von Signalen wurde im vorherigen Abschnitt vorgestellt. In diesem Abschnitt stellen wir vor, wie der Kernel den Signalmechanismus implementiert. Das heißt, wie der Kernel ein Signal an einen Prozess sendet, wie der Prozess ein Signal empfängt, wie der Prozess seine Reaktion auf das Signal steuert, wann und wie der Kernel das vom Prozess empfangene Signal verarbeitet. Ich möchte auch die Rolle vorstellen, die setjmp und longjmp bei Signalen spielen.

1. Grundlegende Signalverarbeitungsmethoden durch den Kernel

Die Art und Weise, wie der Kernel ein Soft-Interrupt-Signal an einen Prozess sendet, besteht darin, das dem Signal entsprechende Bit im Signalfeld des Prozesstabelleneintrags zu setzen, in dem sich der Prozess befindet. Was hier hinzugefügt werden sollte, ist, dass, wenn das Signal an einen schlafenden Prozess gesendet wird, es von der Priorität des Prozesses abhängt, der in den Ruhezustand wechselt. Wenn der Prozess mit einer Priorität schläft, die unterbrochen werden kann, wird der Prozess andernfalls nur aktiviert das Signal im Prozesstabellenfeld entsprechendes Bit, ohne den Prozess aufzuwecken. Dies ist wichtig, da ein Prozess dann prüfen muss, ob ein Signal empfangen wurde, wenn er kurz davor steht, vom Kernelmodus in den Benutzermodus zurückzukehren, oder wenn ein Prozess kurz davor steht, in einen Ruhezustand mit entsprechend niedriger Priorität einzutreten oder diesen zu verlassen.

Der Zeitpunkt, zu dem der Kernel ein von einem Prozess empfangenes Signal verarbeitet, ist, wenn ein Prozess vom Kernelmodus in den Benutzermodus zurückkehrt. Wenn ein Prozess im Kernelmodus ausgeführt wird, wird das Soft-Interrupt-Signal daher nicht sofort wirksam und muss warten, bis er in den Benutzermodus zurückkehrt. Der Prozess kehrt erst nach der Verarbeitung des Signals in den Benutzermodus zurück. Der Prozess verfügt im Benutzermodus über keine unverarbeiteten Signale.

Der Kernel verarbeitet das von einem Prozess empfangene Soft-Interrupt-Signal im Kontext des Prozesses, daher muss sich der Prozess in einem laufenden Zustand befinden. Wie bereits bei der Einführung des Konzepts erwähnt, gibt es drei Arten der Signalverarbeitung: Der Prozess wird beendet, nachdem er das Signal empfangen hat, und nachdem der Prozess das Signal empfangen hat, führt er die vom Benutzer festgelegte Funktion aus, um das Signal aufzurufen das System. Wenn ein Prozess ein Signal empfängt, das er ignoriert, verwirft der Prozess das Signal und fährt fort, als ob das Signal nicht empfangen worden wäre. Wenn der Prozess ein Signal zur Erfassung 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 dieser Ebene wird der Wert der Rücksprungadresse auf die Adresse der benutzerdefinierten Verarbeitungsfunktion gesetzt Wenn der Prozess vom Kernel zurückkehrt und den oberen Rand des Stapels öffnet, kehrt er zur benutzerdefinierten Funktion zurück. Wenn er von der Funktion zurückkehrt und dann den oberen Rand des Stapels öffnet, kehrt er an die Stelle zurück, an der er ursprünglich in den Kernel eingetreten ist . Der Grund dafür ist, dass benutzerdefinierte Verarbeitungsfunktionen nicht im Kernel-Modus ausgeführt werden können und dürfen (wenn die benutzerdefinierte Funktion im Kernel-Modus ausgeführt wird, kann der Benutzer beliebige Berechtigungen erhalten).

Bei der Signalverarbeitungsmethode sollten einige Punkte besonders beachtet werden. Erstens löscht der Kernel in einigen Systemen die Adresse der im Benutzerbereich festgelegten Signalverarbeitungsroutine, wenn ein Prozess ein Interrupt-Signal verarbeitet und in den Benutzermodus zurückkehrt. Dies bedeutet, dass der Prozess das nächste Mal die Signalverarbeitungsmethode ändert Standardwert, es sei denn, der Signalsystemaufruf wird erneut verwendet, bevor das nächste Signal eintrifft. Dies kann dazu führen, dass der Prozess das Signal erhält, bevor er das Signal aufruft, was dazu führt, dass er beendet wird. In BSD löscht der Kernel diese Adresse nicht mehr. Wenn diese Adresse jedoch nicht gelöscht wird, kann es sein, dass der Prozess zu schnell ein Signal erhält und einen Stapelüberlauf verursacht. Um die oben genannte Situation zu vermeiden. Im BSD-System simuliert der Kernel die Verarbeitungsmethode von Hardware-Interrupts, d. h. bei der Verarbeitung eines Interrupts verhindert er den Empfang neuer Interrupts dieses Typs.

Der zweite zu beachtende Punkt ist, dass, wenn das zu erfassende Signal auftritt, während sich der Prozess in einem Systemaufruf befindet und der Prozess auf einer unterbrechbaren Prioritätsebene schläft, das Signal den Prozess dazu veranlasst, einen Longjmp auszuführen und aus dem Ruhezustand zu springen Zustand, kehren Sie in den Benutzermodus zurück und führen Sie die Signalverarbeitungsroutine aus. Bei der Rückkehr aus einer Signalverarbeitungsroutine verhält sich der Prozess so, als wäre er von einem Systemaufruf zurückgekehrt, gibt jedoch einen Fehlercode zurück, der darauf hinweist, dass der Systemaufruf unterbrochen wurde. Es ist zu beachten, dass der Kernel in BSD-Systemen Systemaufrufe automatisch neu starten kann.

Drittes ist zu beachten: Wenn der Prozess auf einer unterbrechbaren Prioritätsstufe schläft und ein Signal zum Ignorieren empfängt, wird der Prozess aufgeweckt, führt jedoch kein longjmp aus und schläft normalerweise weiter. Der Benutzer hat jedoch nicht das Gefühl, dass der Prozess geweckt wurde, sondern es ist, als ob das Signal nicht aufgetreten wäre.

Die vierte Sache, die Sie beachten sollten: Der Kernel behandelt das Signal zur Beendigung des untergeordneten Prozesses (SIGCLD) anders als andere Signale. Wenn ein Prozess überprüft, ob er ein Signal zum Beenden eines untergeordneten Prozesses erhalten hat, verhält sich der Prozess standardmäßig so, als ob er das Signal nicht erhalten hätte. Wenn der übergeordnete Prozess die Systemaufrufwartefunktion ausführt, wird der Prozess durch den Systemaufruf aktiviert Warten und Kehren Sie zum Warteaufruf zurück, führen Sie eine Reihe von Folgevorgängen des Warteaufrufs durch (suchen Sie den untergeordneten Zombie-Prozess, geben Sie den Prozesstabelleneintrag des untergeordneten Prozesses frei) und kehren Sie dann vom Warten zurück. Die Funktion des SIGCLD-Signals besteht darin, einen Prozess aufzuwecken, der auf einer unterbrechbaren Prioritätsebene schläft. Wenn der Prozess das Signal empfängt, geht er wie bei der normalen Signalverarbeitung zur Handler-Routine über. Wenn der Prozess das Signal ignoriert, ist die Aktion der Systemaufrufwartezeit anders, da die Funktion von SIGCLD nur darin besteht, einen Prozess aufzuwecken, der auf der unterbrechbaren Prioritätsebene schläft, und dann den übergeordneten Prozess aufzuwecken, der den Warteaufruf ausführt, und dies auch weiterhin tut Führen Sie den Warteaufruf aus und warten Sie dann auf andere untergeordnete Prozesse.

Wenn ein Prozess den Signalsystemaufruf aufruft und die SIGCLD-Verarbeitungsmethode festlegt und der Prozess einen untergeordneten Prozess im Zombie-Zustand hat, sendet der Kernel ein SIGCLD-Signal an den Prozess.

2. Die Funktionen von setjmp und longjmp

Bei der früheren Einführung des Signalverarbeitungsmechanismus wurden setjmp und longjmp oft erwähnt, ihre Funktionen und Implementierungsmethoden wurden jedoch nicht im Detail erläutert. Hier eine kurze Einführung dazu.

Bei der Einführung von Signalen haben wir mehrere Stellen gesehen, an denen der Prozess direkt vom ursprünglichen Systemaufruf zurückkehren musste, nachdem überprüft wurde, ob das Signal empfangen wurde, anstatt auf den Abschluss des Anrufs zu warten. Diese Situation, in der ein Prozess plötzlich seinen Kontext ändert, ist das Ergebnis der Verwendung von setjmp und longjmp. setjmp speichert den gespeicherten Kontext im Benutzerbereich und setzt die Ausführung im alten Kontext fort. Das heißt, der Prozess führt einen Systemaufruf aus, wenn er aus Ressourcengründen oder aus anderen Gründen in den Ruhezustand wechselt , Der Kernel ruft longjmp für den Prozess auf, damit der Kernel den durch den ursprünglichen setjmp-Aufruf im Benutzerbereich des Prozesses gespeicherten Kontext wiederherstellt, sodass der Prozess in den Zustand vor dem Warten zurückkehren kann für Ressourcen und der Kernel gibt 1 für setjmp zurück, sodass der Prozess weiß, dass der Systemaufruf fehlgeschlagen ist. Das ist es, was sie tun.

3. Systemaufrufe im Zusammenhang mit Signalen

Der größte Teil des Wissens über Signale wurde in den beiden vorherigen Abschnitten vorgestellt. In diesem Abschnitt erfahren Sie mehr über diese Systemaufrufe. Unter diesen wird das Systemaufrufsignal vom Prozess verwendet, um die Verarbeitungsmethode eines bestimmten Signals festzulegen, und das Systemaufruf-Kill wird verwendet, um ein Signal an den angegebenen Prozess zu senden. Diese beiden Aufrufe bilden die Grundfunktion des Signals. Die letzten beiden Aufrufe, Pause und Alarm, sind Prozesspausen und Timer, die durch Signale implementiert werden. Der Aufruf eines Alarms wird verwendet, um den Prozess über den Ablauf des Timers durch Signale zu informieren. Deshalb stellen wir hier auch diese beiden Aufrufe vor.

1. Signalsystemruf

Das Systemaufrufsignal wird verwendet, um die Verarbeitungsmethode eines bestimmten Signals festzulegen. Die Aufrufdeklaration hat das folgende Format:
void (*signal(int signum, void (*handler)(int)))(int);
Fügen Sie mit diesem Aufruf die folgende Header-Datei zum Prozess hinzu:
#include

Das obige Deklarationsformat ist relativ kompliziert. Wenn Sie nicht wissen, wie man es verwendet, können Sie es auch über das folgende Typdefinitionsformat (POSIX-Definition) verwenden typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
Dieses Format verfügt jedoch in verschiedenen Systemen über unterschiedliche Typdefinitionen. Um dieses Format zu verwenden, lesen Sie am besten das Online-Handbuch.

Im Aufruf gibt der Parameter signum das Signal an, das zur Verarbeitung der Methode gesetzt werden soll. Der zweite Parameterhandler ist eine Verarbeitungsfunktion oder

SIG_IGN: Ignorieren Sie das Signal, auf das der Parameter signum zeigt.
SIG_DFL: Stellen Sie die Verarbeitungsmethode des Signals, auf das der Parameter signum zeigt, auf den Standardwert zurück.

Der an die Signalverarbeitungsroutine übergebene ganzzahlige Parameter ist der Signalwert, der es einer Signalverarbeitungsroutine ermöglicht, mehrere Signale zu verarbeiten. Der Rückgabewert des Systemaufrufsignals ist die vorherige Verarbeitungsroutine des angegebenen Signalsignums oder der im Fehlerfall zurückgegebene Fehlercode SIG_ERR. Schauen wir uns ein einfaches Beispiel an:

#include 
\#include 
\#include 
void sigroutine(int dunno) { /* 信号处理例程,其中dunno将会得到信号的值 */ 
switch (dunno) { 
case 1: 
printf("Get a signal -- SIGHUP "); 
break; 
case 2: 
printf("Get a signal -- SIGINT "); 
break; 
case 3: 
printf("Get a signal -- SIGQUIT "); 
break; 
} 
return; 
} 

int main() { 
printf("process id is %d ",getpid()); 
signal(SIGHUP, sigroutine); //* 下面设置三个信号的处理方法 
signal(SIGINT, sigroutine); 
signal(SIGQUIT, sigroutine); 
for (;;) ; 
} 

其中信号SIGINT由按下Ctrl-C发出,信号SIGQUIT由按下Ctrl-发出。该程序执行的结果如下:

localhost:~$ ./sig_test 
process id is 463 
Get a signal -SIGINT //按下Ctrl-C得到的结果 
Get a signal -SIGQUIT //按下Ctrl-得到的结果 
//按下Ctrl-z将进程置于后台 
[1]+ Stopped ./sig_test 
localhost:~$ bg 
[1]+ ./sig_test & 
localhost:~$ kill -HUP 463 //向进程发送SIGHUP信号 
localhost:~$ Get a signal – SIGHUP 
kill -9 463 //向进程发送SIGKILL信号,终止进程 
localhost:~$ 

2、kill 系统调用

系统调用kill用来向进程发送一个信号。该调用声明的格式如下:
int kill(pid_t pid, int sig);
在使用该调用的进程中加入以下头文件:

\#include 
\#include 

该 系统调用可以用来向任何进程或进程组发送任何信号。如果参数pid是正数,那么该调用将信号sig发送到进程号为pid的进程。如果pid等于0,那么信 号sig将发送给当前进程所属进程组里的所有进程。如果参数pid等于-1,信号sig将发送给除了进程1和自身以外的所有进程。如果参数pid小于- 1,信号sig将发送给属于进程组-pid的所有进程。如果参数sig为0,将不发送信号。该调用执行成功时,返回值为0;错误时,返回-1,并设置相应 的错误代码errno。下面是一些可能返回的错误代码:
EINVAL:指定的信号sig无效。
ESRCH:参数pid指定的进程或进程组不存在。注意,在进程表项中存在的进程,可能是一个还没有被wait收回,但已经终止执行的僵死进程。
EPERM: 进程没有权力将这个信号发送到指定接收信号的进程。因为,一个进程被允许将信号发送到进程pid时,必须拥有root权力,或者是发出调用的进程的UID 或EUID与指定接收的进程的UID或保存用户ID(savedset-user-ID)相同。如果参数pid小于-1,即该信号发送给一个组,则该错误 表示组中有成员进程不能接收该信号。

3、pause系统调用

系统调用pause的作用是等待一个信号。该调用的声明格式如下:
int pause(void);
在使用该调用的进程中加入以下头文件:
#include

该调用使得发出调用的进程进入睡眠,直到接收到一个信号为止。该调用总是返回-1,并设置错误代码为EINTR(接收到一个信号)。下面是一个简单的范例:

#include 
\#include 
\#include 
void sigroutine(int unused) { 
printf("Catch a signal SIGINT "); 
} 

int main() { 
signal(SIGINT, sigroutine); 
pause(); 
printf("receive a signal "); 
} 

在这个例子中,程序开始执行,就象进入了死循环一样,这是因为进程正在等待信号,当我们按下Ctrl-C时,信号被捕捉,并且使得pause退出等待状态。

4、alarm和 setitimer系统调用

系统调用alarm的功能是设置一个定时器,当定时器计时到达时,将发出一个信号给进程。该调用的声明格式如下:
unsigned int alarm(unsigned int seconds);
在使用该调用的进程中加入以下头文件:
#include

系 统调用alarm安排内核为调用进程在指定的seconds秒后发出一个SIGALRM的信号。如果指定的参数seconds为0,则不再发送 SIGALRM信号。后一次设定将取消前一次的设定。该调用返回值为上次定时调用到发送之间剩余的时间,或者因为没有前一次定时调用而返回0。

注意,在使用时,alarm只设定为发送一次信号,如果要多次发送,就要多次使用alarm调用。

对于alarm,这里不再举例。现在的系统中很多程序不再使用alarm调用,而是使用setitimer调用来设置定时器,用getitimer来得到定时器的状态,这两个调用的声明格式如下:
int getitimer(int which, struct itimerval *value);
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue);
在使用这两个调用的进程中加入以下头文件:
#include

该系统调用给进程提供了三个定时器,它们各自有其独有的计时域,当其中任何一个到达,就发送一个相应的信号给进程,并使得计时器重新开始。三个计时器由参数which指定,如下所示:
TIMER_REAL:按实际时间计时,计时到达将给进程发送SIGALRM信号。
ITIMER_VIRTUAL:仅当进程执行时才进行计时。计时到达将发送SIGVTALRM信号给进程。
ITIMER_PROF:当进程执行时和系统为该进程执行动作时都计时。与ITIMER_VIR-TUAL是一对,该定时器经常用来统计进程在用户态和内核态花费的时间。计时到达将发送SIGPROF信号给进程。

定时器中的参数value用来指明定时器的时间,其结构如下:

struct itimerval { 
struct timeval it_interval; /* 下一次的取值 */ 
struct timeval it_value; /* 本次的设定值 */ 
}; 

该结构中timeval结构定义如下: 
struct timeval { 
long tv_sec; /* 秒 */ 
long tv_usec; /* 微秒,1秒 = 1000000 微秒*/ 
}; 

在setitimer 调用中,参数ovalue如果不为空,则其中保留的是上次调用设定的值。定时器将it_value递减到0时,产生一个信号,并将it_value的值设 定为it_interval的值,然后重新开始计时,如此往复。当it_value设定为0时,计时器停止,或者当它计时到期,而it_interval 为0时停止。调用成功时,返回0;错误时,返回-1,并设置相应的错误代码errno:
EFAULT:参数value或ovalue是无效的指针。
EINVAL:参数which不是ITIMER_REAL、ITIMER_VIRT或ITIMER_PROF中的一个。

下面是关于setitimer调用的一个简单示范,在该例子中,每隔一秒发出一个SIGALRM,每隔0.5秒发出一个SIGVTALRM信号:

#include 
\#include 
\#include 
\#include 
int sec; 

void sigroutine(int signo) { 
switch (signo) { 
case SIGALRM: 
printf("Catch a signal -- SIGALRM "); 
break; 
case SIGVTALRM: 
printf("Catch a signal -- SIGVTALRM "); 
break; 
} 
return; 
} 

int main() { 
struct itimerval value,ovalue,value2; 
sec = 5; 

printf("process id is %d ",getpid()); 
signal(SIGALRM, sigroutine); 
signal(SIGVTALRM, sigroutine); 

value.it_value.tv_sec = 1; 
value.it_value.tv_usec = 0; 
value.it_interval.tv_sec = 1; 
value.it_interval.tv_usec = 0; 
setitimer(ITIMER_REAL, &value, &ovalue); 

value2.it_value.tv_sec = 0; 
value2.it_value.tv_usec = 500000; 
value2.it_interval.tv_sec = 0; 
value2.it_interval.tv_usec = 500000; 
setitimer(ITIMER_VIRTUAL, &value2, &ovalue); 

for (;;) ; 
} 

该例子的屏幕拷贝如下:

localhost:~$ ./timer_test 
process id is 579 
Catch a signal – SIGVTALRM 
Catch a signal – SIGALRM 
Catch a signal – SIGVTALRM 
Catch a signal – SIGVTALRM 
Catch a signal – SIGALRM 
Catch a signal –GVTALRM

通过本文,你应该对 Linux 下的信号机制有了一个深入的了解,知道了它的定义、原理、用法和优缺点。你也应该明白了信号机制的作用和影响,以及如何在 Linux 下正确地使用和处理信号。我们建议你在使用 Linux 系统时,使用信号机制来提高系统的响应性和灵活性。同时,我们也提醒你在使用信号机制时要注意一些潜在的问题和挑战,如信号丢失、信号屏蔽、信号安全等。希望本文能够帮助你更好地使用 Linux 系统,让你在 Linux 下掌握信号机制的使用和处理。

Das obige ist der detaillierte Inhalt vonSignalmechanismus unter Linux: Verwendung von Signalen für die Kommunikation und Steuerung zwischen Prozessen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:lxlinux.net. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen