Maison > Tutoriel système > Linux > le corps du texte

Mécanisme de signal sous Linux : Comment utiliser les signaux pour la communication et le contrôle inter-processus

WBOY
Libérer: 2024-02-12 12:40:03
avant
1121 Les gens l'ont consulté

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

Le signal est une méthode de communication et de contrôle inter-processus couramment utilisée dans les systèmes Linux. Il permet à un processus d'envoyer un message simple à un autre processus pour l'informer qu'un certain événement ou statut s'est produit. La fonction des signaux est d'améliorer la réactivité et la flexibilité du système pour faire face à certaines situations anormales ou d'urgence. Dans le système Linux, il existe de nombreux types de signaux, tels que SIGINT, SIGTERM, SIGKILL, etc. Chacun d'eux a sa propre signification et fonction et convient à différents scénarios et besoins. Mais comprenez-vous vraiment le mécanisme du signal sous Linux ? Savez-vous comment utiliser les signaux pour la communication et le contrôle inter-processus sous Linux ? Savez-vous comment gérer et ignorer les signaux sous Linux ? Cet article vous présentera en détail les connaissances pertinentes du mécanisme de signal sous Linux, vous permettant de mieux utiliser et comprendre cette puissante méthode de communication et de contrôle inter-processus sous Linux.

1.Concepts de base des signaux

Cette section présente d'abord quelques concepts de base sur les signaux, puis donne quelques types de signaux de base et événements correspondant aux signaux. Les concepts de base sont particulièrement importants pour comprendre et utiliser les signaux, ainsi que pour comprendre les mécanismes de signalisation. Voyons ce qu'est un signal.

1.Concepts de base

Le signal d'interruption douce (signal, également appelé signal) est utilisé pour informer le processus qu'un événement asynchrone s'est produit. Les processus peuvent s'envoyer des signaux d'interruption logicielle via l'appel système kill. Le noyau peut également envoyer des signaux au processus en raison d'événements internes, l'informant qu'un événement s'est produit. Notez que les signaux ne sont utilisés que pour informer un processus des événements qui se sont produits et ne transmettent aucune donnée au processus.

Le processus qui reçoit le signal a différentes méthodes de traitement pour différents signaux. Les méthodes de traitement peuvent être divisées en trois catégories : la première est un gestionnaire de type interruption. Pour le signal qui doit être traité, le processus peut spécifier une fonction de traitement qui le gérera. La deuxième méthode consiste à ignorer un signal et à ne rien faire avec ce signal, comme si cela ne s'était jamais produit. La troisième méthode consiste à conserver la valeur par défaut du système pour traiter le signal. Cette opération par défaut, l'opération par défaut pour la plupart des signaux consiste à terminer le processus. Le processus utilise le signal d'appel système pour spécifier le comportement de traitement du processus pour un certain signal.

Il y a un champ de signal d'interruption logicielle dans l'entrée de la table de processus. Chaque bit de ce champ correspond à un signal lorsqu'un signal est envoyé au processus, le bit correspondant est défini. On peut voir de là que le processus peut retenir différents signaux en même temps, mais pour un même signal, le processus ne sait pas combien sont venus avant le traitement.

2. Type de signal

Il existe de nombreuses raisons d'envoyer des signaux. Voici des classifications simples selon les raisons d'envoyer des signaux pour comprendre divers signaux :

(1) Signaux liés à la fin du processus. Ce type de signal est émis lorsque le processus se termine ou que le processus enfant se termine.
(2) Signaux liés aux événements d'exception de processus. Par exemple, le processus franchit la limite, ou tente d'écrire dans une zone de mémoire en lecture seule (telle que la zone de texte du programme), ou exécute une instruction privilégiée et diverses autres erreurs matérielles.
(3) Signaux liés à la rencontre de conditions irrécupérables lors des appels système. Par exemple, lors de l'exécution de l'appel système exec, les ressources d'origine ont été libérées et les ressources système actuelles ont été épuisées.
(4) Signaux liés à la rencontre de conditions d'erreur non prédictives lors de l'exécution d'appels système. Comme exécuter un appel système qui n’existe pas.
(5) Signaux envoyés par les processus en mode utilisateur. Par exemple, un processus appelle l'appel système kill pour envoyer des signaux à d'autres processus.
(6) Signaux liés à l'interaction du terminal. Par exemple, l'utilisateur ferme un terminal ou appuie sur la touche pause.
(7) Suivre les signaux d'exécution du processus.

La liste des signaux pris en charge par Linux est la suivante. De nombreux signaux sont liés à l'architecture de la machine. Les premiers répertoriés sont les signaux répertoriés dans POSIX.1 :

Valeur du signal Action de traitement Raison de l'envoi du signal
———————————————————————-

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 后台进程企图从控制终端写 
Copier après la connexion

Les signaux suivants ne sont pas répertoriés dans POSIX.1, mais sont répertoriés dans SUSv2

Valeur du signal Action de traitement Raison de l'envoi du signal
——————————————————————–

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))。 
Copier après la connexion

Voici quelques autres signaux

Valeur du signal Action de traitement Raison de l'envoi du signal
———————————————————————-

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) 
Copier après la connexion

(Ici, - signifie que le signal n'est pas implémenté ; il y a trois valeurs​​étant donné la signification, la première valeur est généralement valable sur Alpha et Sparc, la valeur du milieu correspond à i386 et ppc et sh, et la dernière la valeur correspond au signal mips 29 SIGINFO/SIGPWR sur Alpha, SIGLOST sur Sparc)

La signification des lettres dans l'élément d'action de traitement est la suivante
A L'action par défaut est de terminer le processus
B L'action par défaut est d'ignorer ce signal
L'action par défaut de C est de terminer le processus et d'effectuer un vidage d'image du noyau (dump core)
D L'action par défaut est d'arrêter le processus
Le signal E ne peut pas être capturé
Le signal F ne peut pas être ignoré

Les signaux introduits ci-dessus sont pris en charge par des systèmes courants. Les noms, fonctions et actions de traitement des différents signaux par défaut sont présentés sous forme de tableau. Les significations des différentes actions de traitement par défaut sont : terminer le programme signifie que le processus se termine ; ignorer le signal signifie ignorer le signal sans le traiter ; signifie que le programme se bloque et peut être redémarré après être entré dans l'état arrêté, généralement pendant ; le débogage (comme l'appel système ptrace) ; le vidage de l'image du noyau fait référence au vidage de l'image des données de processus en mémoire et d'une partie du contenu stocké dans la structure du noyau du processus vers le système de fichiers dans un certain format, et le processus quitte l'exécution. De cette façon, l'avantage est qu'il offre aux programmeurs la commodité d'obtenir des valeurs de données pendant l'exécution du processus, leur permettant de déterminer la cause du vidage et de déboguer leurs programmes.

Notez que les signaux SIGKILL et SIGSTOP ne peuvent être ni captés ni ignorés. Les signaux SIGIOT et SIGABRT forment un seul signal. On peut voir qu'un même signal peut avoir des valeurs différentes selon les systèmes, il est donc recommandé d'utiliser le nom défini pour le signal plutôt que d'utiliser directement la valeur du signal.

2. Mécanisme de signal

Le concept de base des signaux a été introduit dans la section précédente, nous présenterons comment le noyau implémente le mécanisme de signal. C'est-à-dire comment le noyau envoie un signal à un processus, comment le processus reçoit un signal, comment le processus contrôle sa réponse au signal, quand et comment le noyau traite le signal reçu par le processus. Je voudrais également présenter le rôle que jouent setjmp et longjmp dans les signaux.

1. Méthodes de base de traitement du signal par le noyau

La façon dont le noyau envoie un signal d'interruption logicielle à un processus consiste à définir le bit correspondant au signal dans le champ de signal de l'entrée de la table de processus où se trouve le processus. Ce qu'il faut ajouter ici, c'est que si le signal est envoyé à un processus en veille, cela dépend de la priorité du processus qui entre en veille. Si le processus dort avec une priorité qui peut être interrompue, le processus est réveillé sinon seul le processus. Le signal dans la table de processus est défini sur le champ correspondant au bit sans réveiller le processus. Ceci est important car le moment où un processus vérifie si un signal a été reçu est lorsqu'un processus est sur le point de revenir du mode noyau au mode utilisateur ou lorsqu'un processus est sur le point d'entrer ou de sortir d'un état de veille de faible priorité appropriée ;

Le moment auquel le noyau traite un signal reçu par un processus correspond au moment où un processus revient du mode noyau au mode utilisateur. Par conséquent, lorsqu'un processus s'exécute en mode noyau, le signal d'interruption logicielle ne prend pas effet immédiatement et doit attendre qu'il revienne en mode utilisateur. Le processus reviendra en mode utilisateur seulement après avoir traité le signal. Le processus n'aura pas de signaux non traités en mode utilisateur.

Le noyau gère le signal d'interruption logicielle reçu par un processus dans le contexte du processus, le processus doit donc être en cours d'exécution. Comme mentionné précédemment lors de l'introduction du concept, il existe trois types de traitement du signal : le processus se termine après avoir reçu le signal ; le processus ignore le signal et après que le processus a reçu le signal, il exécute la fonction définie par l'utilisateur pour appeler le signal ; le système. Lorsqu'un processus reçoit un signal qu'il ignore, il ignore le signal et continue comme si le signal n'avait pas été reçu. Si le processus reçoit un signal à capturer, la fonction définie par l'utilisateur est exécutée lorsque le processus revient du mode noyau au mode utilisateur. De plus, la méthode d'exécution des fonctions définies par l'utilisateur est très intelligente. Le noyau crée une nouvelle couche sur la pile utilisateur, dans cette couche, la valeur de l'adresse de retour est définie sur l'adresse de la fonction de traitement définie par l'utilisateur, de sorte que. lorsque le processus revient du noyau et fait apparaître le haut de la pile, il revient à la fonction définie par l'utilisateur, et lorsqu'il revient de la fonction et fait apparaître le haut de la pile, il revient à l'endroit où il est entré à l'origine dans le noyau. La raison en est que les fonctions de traitement définies par l'utilisateur ne peuvent pas et ne sont pas autorisées à être exécutées en mode noyau (si la fonction définie par l'utilisateur s'exécute en mode noyau, l'utilisateur peut obtenir n'importe quelle autorisation).

Il y a quelques points auxquels il convient de prêter une attention particulière dans la méthode de traitement du signal. Premièrement, dans certains systèmes, lorsqu'un processus gère un signal d'interruption et revient en mode utilisateur, le noyau efface l'adresse de la routine de traitement du signal définie dans la zone utilisateur, c'est-à-dire la prochaine fois que le processus modifie la méthode de traitement du signal. valeur par défaut, sauf si l'appel du système de signalisation est à nouveau utilisé avant l'arrivée du signal suivant. Cela peut amener le processus à obtenir le signal avant d'appeler le signal, ce qui entraîne sa sortie. Sous BSD, le noyau n'efface plus cette adresse. Mais ne pas effacer cette adresse peut amener le processus à recevoir un signal trop rapidement et provoquer un débordement de pile. Afin d'éviter la situation ci-dessus. Dans le système BSD, le noyau simule la méthode de traitement des interruptions matérielles, c'est-à-dire que lors du traitement d'une interruption, il empêche la réception de nouvelles interruptions de ce type.

La deuxième chose à noter est que si le signal à capturer se produit lorsque le processus est dans un appel système et que le processus se met en veille à un niveau de priorité pouvant être interrompu, alors le signal amène le processus à effectuer un longjmp et à sortir du mode veille. state , revenez en mode utilisateur et exécutez la routine de traitement du signal. Au retour d'une routine de gestion de signal, le processus se comporte comme s'il revenait d'un appel système, mais renvoie un code d'erreur indiquant que l'appel système a été interrompu. Il convient de noter que dans les systèmes BSD, le noyau peut redémarrer automatiquement les appels système.

La troisième chose à noter : si le processus dort à un niveau de priorité disruptible, lorsqu'il reçoit un signal à ignorer, le processus est réveillé, mais ne fait pas de longjmp et continue généralement de dormir. Mais l’utilisateur n’a pas l’impression que le processus a été réveillé, mais c’est comme si le signal ne s’était pas produit.

La quatrième chose à noter : la gestion par le noyau du signal de fin de processus enfant (SIGCLD) est différente des autres signaux. Lorsqu'un processus vérifie qu'il a reçu un signal pour terminer un processus enfant, par défaut, le processus agit comme s'il n'avait pas reçu le signal. Si le processus parent exécute l'attente de l'appel système, le processus se réveillera de l'appel système. attendez et revenez à l'appel d'attente, effectuez une série d'opérations de suivi de l'appel d'attente (trouver le processus enfant zombie, libérer l'entrée de la table de processus du processus enfant), puis revenir de l'attente. La fonction du signal SIGCLD est de réveiller un processus endormi à un niveau de priorité disruptible. Si le processus capte le signal, il est transmis à la routine de gestion, tout comme la gestion normale du signal. Si le processus ignore le signal, l'action de l'appel système en attente est différente, car la fonction de SIGCLD est uniquement de réveiller un processus endormi à un niveau de priorité interruption, alors le processus parent qui exécute l'appel en attente est réveillé et continue à exécutez l'appel d'attente. Opérations suivantes, puis attendez les autres processus enfants.

Si un processus appelle l'appel système signal et définit la méthode de traitement SIGCLD, et que le processus a un processus enfant dans un état zombie, le noyau enverra un signal SIGCLD au processus.

2. Les fonctions de setjmp et longjmp

Lors de l'introduction du mécanisme de traitement du signal plus tôt, setjmp et longjmp ont été mentionnés à plusieurs reprises, mais leurs fonctions et méthodes de mise en œuvre n'ont pas été expliquées en détail. Voici une brève introduction à cela.

Lors de l'introduction des signaux, nous avons vu plusieurs endroits exigeant que le processus revienne directement de l'appel système d'origine après avoir vérifié que le signal est reçu, plutôt que d'attendre la fin de l'appel. Cette situation où un processus change soudainement de contexte est le résultat de l'utilisation de setjmp et longjmp. setjmp stocke le contexte enregistré dans la zone utilisateur et continue l'exécution dans l'ancien contexte. C'est-à-dire que le processus exécute un appel système lorsqu'il se met en veille pour des raisons de ressources ou pour d'autres raisons, le noyau effectue un setjmp pour le processus s'il est réveillé par un signal pendant le sommeil et que le processus ne peut pas se rendormir. , le noyau appelle longjmp pour le processus. Cette opération permet au noyau de restaurer le contexte enregistré dans la zone utilisateur du processus par l'appel setjmp d'origine au contexte actuel, afin que le processus puisse revenir à l'état avant d'attendre. pour les ressources, et le noyau renvoie 1 pour setjmp, afin que le processus sache que l'appel système a échoué. C'est ce qu'ils font.

3. Appels système liés aux signaux

La plupart des connaissances sur les signaux ont été introduites dans les deux sections précédentes. Dans cette section, nous découvrirons ces appels système. Parmi eux, le signal d'appel système est utilisé par le processus pour définir la méthode de traitement d'un certain signal, et l'appel système kill est utilisé pour envoyer un signal au processus spécifié. Ces deux appels constituent le fonctionnement de base du signal. Les deux derniers appels, pause et alarme, sont des pauses de processus et des minuteries mises en œuvre via des signaux. L'alarme d'appel est utilisée pour notifier le processus de l'expiration de la minuterie via des signaux. Donc ici, nous présentons également ces deux appels.

1. appel du système de signalisation

Le signal d'appel système est utilisé pour définir la méthode de traitement d'un certain signal. La déclaration d'appel a le format suivant :
void (*signal(int signum, void (*handler)(int)))(int);
Ajoutez le fichier d'en-tête suivant au processus à l'aide de cet appel :
#inclure

Le format de déclaration ci-dessus est relativement compliqué. Si vous ne savez pas comment l'utiliser, vous pouvez également l'utiliser via le format de définition de type suivant (définition POSIX) :
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
Cependant, ce format a différentes définitions de type selon les systèmes, donc pour utiliser ce format, il est préférable de se référer au manuel en ligne.

Dans l'appel, le paramètre signum indique le signal à définir pour gérer la méthode. Le deuxième gestionnaire de paramètres est une fonction de traitement, ou
SIG_IGN : ignore le signal pointé par le paramètre signum.
SIG_DFL : Restaure la méthode de traitement du signal pointé par le paramètre signum à la valeur par défaut.

Le paramètre entier transmis à la routine de traitement du signal est la valeur du signal, ce qui permet à une routine de traitement du signal de traiter plusieurs signaux. La valeur de retour du signal d'appel système est la routine de traitement précédente du signal de signal spécifié ou le code d'erreur SIG_ERR renvoyé en cas d'erreur. Regardons un exemple simple :

#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 (;;) ; 
} 
Copier après la connexion

其中信号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:~$ 
Copier après la connexion

2、kill 系统调用

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

\#include 
\#include 
Copier après la connexion

该 系统调用可以用来向任何进程或进程组发送任何信号。如果参数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 "); 
} 
Copier après la connexion

在这个例子中,程序开始执行,就象进入了死循环一样,这是因为进程正在等待信号,当我们按下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 微秒*/ 
}; 
Copier après la connexion

在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 (;;) ; 
} 
Copier après la connexion

该例子的屏幕拷贝如下:

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
Copier après la connexion

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

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:lxlinux.net
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!