2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Le signal (signal) est une interruption logicielle. C'est une méthode de transmission de messages entre les processus. Il est utilisé pour informer le processus qu'un événement s'est produit, mais il ne peut transmettre aucune donnée au processus.
Il existe de nombreuses raisons pour lesquelles des signaux sont générés dans le Shell, vous pouvez les utiliser.kill
etkillall
Commande pour envoyer le signal :
kill -信号的类型 进程编号
killall -信号的类型 进程名
nom du signal | valeur du signal | Action de traitement par défaut | Raison de la signalisation |
---|---|---|---|
INSCRIVEZ-VOUS | 1 | UN | Le terminal se bloque ou le processus de contrôle se termine |
Signal d'information | 2 | UN | Interruption du clavier Ctrl+c |
SIGQUIT | 3 | C | La touche d'échappement du clavier est enfoncée |
SIGILLE | 4 | C | Enseignement illégal |
SIGTRIP (piège à signaux) | 5 | C | instructions de point d'arrêt |
SIGABRT | 6 | C | Signal d'abandon émis par abort(3) |
SIGBUS | 7 | C | erreur de bus |
SIGFPE | 8 | C | exception à virgule flottante |
Sigkill | 9 | UN | kill -9 tue le processus, ce signal ne peut pas être capté et ignoré |
SIGUSR1 | 10 | UN | Signal défini par l'utilisateur 1 |
SIGSEGV | 11 | C | Référence mémoire invalide (tableau hors limites, opération de pointeur nul) |
SIGUSR2 | 12 | UN | Signal défini par l'utilisateur 2 |
Tuyau SIG | 13 | UN | Écrire des données dans un tube sans processus de lecture |
SIGALRM | 14 | UN | Signal de réveil, signal envoyé par la fonction alarm() |
TERME DE SIG | 15 | UN | Signal de terminaison, le signal envoyé par défaut |
SIGSTKFLT | 16 | UN | erreur de pile |
SIGCHLD | 17 | B | Émis à la fin du processus enfant |
SIGCONT | 18 | D | Reprendre un processus arrêté |
ARRÊT SIGS | 19 | D | Arrêter le processus |
SIGTSTP | 20 | D | Terminal appuyer sur la touche stop |
SIGTTIN | 21 | D | Demandes de processus en arrière-plan pour lire le terminal |
SIGTTOU | 22 | D | Le processus en arrière-plan demande à écrire sur le terminal |
SIGURG | 23 | B | Détection des conditions d'urgence (prises) |
Processeur SIGX | 24 | C | Limite de temps CPU dépassée |
SIGXFSZ | 25 | C | Limite de taille de fichier dépassée |
SIGNALRM | 26 | UN | signal d'horloge virtuelle |
SIGPROF | 27 | UN | Analyser les signaux d'horloge |
TREUIL SIG | 28 | B | Modifications de la taille de la fenêtre |
Sondage SIG | 29 | B | Interrogation (Sys V) |
SIGPWR | 30 | UN | panne d'électricité |
SIGSYS | 31 | C | Appel système illégal |
L'action par défaut de A est de terminer le processus.
L'action par défaut de B est d'ignorer ce signal.
L'action par défaut de C consiste à terminer le processus et à effectuer un vidage de l'image du noyau.
L'action par défaut de D est d'arrêter le processus et le programme qui entre dans l'état arrêté peut continuer à s'exécuter.
Il existe trois manières pour les processus de gérer les signaux :
signal()
Les fonctions peuvent définir la manière dont le programme gère les signaux.
Déclaration de fonction :
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
Description du paramètre :
sig
:Spécifiez le signal à capturer.func
: Pointeur vers la fonction de traitement du signal. La fonction de traitement doit recevoir un paramètre entier, qui est le numéro du signal capturé.SIG_DFL
La macro :SIG_DFL représente la méthode de traitement du signal par défaut.utiliserSIG_DFL
commesignal
Le deuxième paramètre de la fonction indique que la méthode de traitement par défaut du système est utilisée pour le signal.SIG_IGN
La macro :SIG_IGN signifie ignorer le signal.utiliserSIG_IGN
commesignal
Le deuxième paramètre de la fonction indique que lorsque le processus recevra le signal, il l'ignorera et n'effectuera aucun traitement. Cela peut empêcher les processus de s'arrêter ou d'être interrompus de manière inattendue dans certaines circonstances.SIG_ERR
:SIG_ERR
Les macros sont utilisées pour indiquer les erreurs.ce n'est pas commesignal
Le deuxième paramètre de la fonction est utilisé à la place commesignal
La valeur de retour de la fonction indique que l'appel a échoué.sisignal
Si l'appel à la fonction échoue, elle renverraSIG_ERR
.Ceci est généralement utilisé pour détecter et traitersignal
Erreur dans l'appel de fonction.Le programme de service s'exécute en arrière-plan. Si vous souhaitez l'arrêter, le tuer n'est pas une bonne idée, car lorsque le processus est arrêté, il s'arrête soudainement et aucun travail ultérieur n'est organisé.
Si vous envoyez un signal au programme de service, après avoir reçu le signal, le programme de service appelle une fonction et écrit le code de conséquence dans la fonction, et le programme peut se terminer de manière planifiée.
L'envoi d'un signal de 0 au programme de service peut détecter si le programme est actif.
Le système d'exploitation Linux fournit kill
etkillall
La commande envoie un signal au programme. Dans le programme, vous pouvez utiliser.kill()
Les fonctions de la bibliothèque envoient des signaux à d'autres processus.
Déclaration de fonction :
int kill(pid_t pid, int sig);
kill()
La fonction prend les paramètressig
Le signal spécifié est transmis au paramètrepid
processus spécifié.
paramètre pid
Il existe plusieurs situations :
pid > 0
Transmettez le signal au processus commepid
processus.pid = 0
Transmettez le signal à tous les processus du même groupe de processus que le processus actuel. Il est souvent utilisé par le processus parent pour envoyer des signaux au processus enfant. Notez que ce comportement dépend de l'implémentation du système.pid < -1
Transmettez le signal à l'ID du groupe de processus de|pid|
de tous les processus.pid = -1
Transmet le signal à tous les processus autorisés à envoyer le signal, mais pas au processus qui a envoyé le signal.Il existe 8 façons de terminer un processus, dont 5 sont des terminaisons normales, à savoir :
main()
Pour les fonctionsreturn
retour;exit()
fonction;_exit()
ou_Exit()
fonction;return
retour;pthread_exit()
retour;Il existe trois manières de terminer anormalement :
abort()
fonction d'abandon ;exister main()
Dans la fonction,return
La valeur renvoyée est le statut de résiliation, sinonreturn
déclaration ou appelexit()
, alors l'état de fin du processus est 0.
Dans le shell, affichez l'état de fin du processus :
echo $?
3 fonctions pour terminer le processus normalement (exit()
et_Exit()
est spécifié par ISO C,_exit()
est spécifié par POSIX) :
void exit(int status);
void _exit(int status);
void _Exit(int status);
status
L’état de fin du processus.
return
Indique qu'au retour de la fonction, le destructeur de l'objet local sera appelé.main()
en fonctionreturn
Le destructeur de l'objet global est également appelé.exit()
Indique de terminer le processus, le destructeur de l'objet local ne sera pas appelé, seul le destructeur de l'objet global sera appelé._exit()
et_Exit()
Sortez directement et aucun travail de nettoyage ne sera effectué.Le processus est disponible atexit()
L'enregistrement des fonctions termine les fonctions (jusqu'à 32), ces fonctions serontexit()
Appelé automatiquement.
int atexit(void (*function)(void));
exit()
L'ordre dans lequel les fonctions de terminaison sont appelées est inversé à partir du moment de l'inscription.
system()
La fonction fournit une méthode simple pour exécuter le programme, en transmettant le programme et les paramètres qui doivent être exécutés sous forme de chaîne.system()
Fonctionnez simplement.
Déclaration de fonction :
int system(const char * string);
system()
La valeur de retour de la fonction est plus gênante.
system()
La fonction renvoie une valeur différente de zéro ;system()
La fonction renvoie 0 ;system()
La fonction renvoie une valeur différente de zéro.exec
Les familles de fonctions offrent un autre moyen d'appeler des programmes (binaires ou scripts shell) au sein d'un processus.
exec
La famille de fonctions est déclarée comme suit :
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);
Avis:
errno
milieu.exec
Après cela, le programme appelé remplacera le programme appelant, c'est-à-direexec
Aucun code après la fonction ne sera exécuté.execl()
etexecv()
, d'autres sont rarement utilisés.Tous les processus de l'ensemble du système Linux sont dans une structure arborescente.
utiliserpstree
Vous pouvez visualiser l'arborescence des processus avec la commande :
pstree -p 进程编号
Chaque processus possède un ID de processus unique représenté par un entier non négatif. Bien qu’uniques, les ID de processus peuvent être réutilisés. Lorsqu'un processus se termine, son ID de processus devient candidat à la réutilisation. Linux utilise un algorithme de réutilisation retardée afin que l'ID d'un processus nouvellement créé soit différent de l'ID utilisé par le processus récemment terminé. Cela évite que de nouveaux processus soient confondus avec un processus terminé utilisant le même ID.
Fonction pour obtenir l'ID du processus :
pid_t getpid(void); // 获取当前进程的ID。
pid_t getppid(void); // 获取父进程的ID。
Un processus existant peut appelerfork()
La fonction crée un nouveau processus.
Déclaration de fonction :
pid_t fork(void);
Dépend defork()
Le nouveau processus créé est appelé processus enfant.
fork()
La fonction est appelée une fois mais renvoie deux fois. La différence entre les deux retours est que la valeur de retour du processus enfant est 0, tandis que la valeur de retour du processus parent est l'ID de processus du processus enfant nouvellement créé.
Le processus enfant et le processus parent continuent de s'exécuterfork()
Le code après ça, Le processus enfant est une copie du processus parent. Le processus enfant possède une copie de l'espace de données, du tas et de la pile du processus parent (remarque : le processus enfant possède une copie, non partagée avec le processus parent).
fork()
Après cela, l'ordre d'exécution des processus parent et enfant n'est pas défini.
fork()
, laissez le processus enfant gérer ces demandes, pendant que le processus parent continue d'attendre la prochaine demande de connexion.fork()
Appelé immédiatement après le retourexec
。fork()
Une fonctionnalité est que les descripteurs de fichiers ouverts dans le processus parent seront copiés dans le processus enfant, et que le processus parent et le processus enfant partagent le même décalage de fichier.
Si un processus parent et un processus enfant écrivent dans un fichier pointé par le même descripteur sans aucune forme de synchronisation, leurs sorties peuvent être mélangées.
À ce stade, vous pouvez constater qu’il n’existe que 100 000 lignes de données.
À l'heure actuelle, il devrait y avoir 200 000 lignes de données. Une ligne de moins peut être due au fait que l'opération d'écriture du fichier n'est pas atomique. En l'absence de mécanisme de synchronisation, deux processus peuvent tenter d'écrire différentes parties du fichier en même temps. provoquant l'échec de l'écriture. Les données interfèrent les unes avec les autres.
vfork()
Les appels de fonction et les valeurs de retour sont les mêmes quefork()
Idem, mais leur sémantique est différente.
vfork()
La fonction est utilisée pour créer un nouveau processus dont le but estexec
Un nouveau programme qui ne copie pas l'espace d'adressage du processus parent car le processus enfant appelle immédiatementexec
, donc l'espace d'adressage du processus parent ne sera pas utilisé. Si le processus enfant utilise l'espace d'adressage du processus parent, des résultats inconnus peuvent se produire.
vfork()
etfork()
Une autre différence est :vfork()
Assurez-vous que le processus enfant s'exécute en premier et appelez-le dans le processus enfantexec
ouexit
Ensuite, le processus parent reprend ses opérations.
Dans le système d'exploitation, un processus zombie fait référence à un processus enfant qui s'est terminé mais que son processus parent n'a pas encore lu son statut de sortie. Bien que le processus zombie ne soit plus en cours d'exécution, il occupe toujours une entrée dans la table des processus afin que le noyau puisse enregistrer les informations sur l'état de sortie du processus (telles que l'ID du processus, l'état de sortie, etc.) jusqu'à ce que le processus parent lise ces informations.
Si le processus parent se termine avant le processus enfant, le processus enfant sera hébergé par le processus 1 (c'est également un moyen de laisser le processus s'exécuter en arrière-plan).
Si le processus enfant se termine avant le processus parent et que le processus parent ne traite pas les informations de sortie du processus enfant, alors le processus enfant deviendra un processus zombie.
Le noyau conserve une structure de données pour chaque processus enfant, y compris le numéro de processus, l'état de fin, le temps CPU utilisé, etc. Si le processus parent traite les informations de sortie du processus enfant, le noyau publiera cette structure de données. Si le processus parent ne traite pas les informations de sortie du processus enfant, le noyau ne publiera pas cette structure de données et le numéro de processus du processus enfant sera toujours occupé. Les numéros de processus disponibles dans le système sont limités. Si un grand nombre de processus zombies sont générés, le système ne pourra pas générer de nouveaux processus car aucun numéro de processus n'est disponible.
signal(SIGCHLD, SIG_IGN)
Informez le noyau qu'il n'est pas intéressé par la sortie du processus enfant et sa structure de données sera publiée immédiatement après la sortie du processus enfant.wait()
/waitpid()
fonction: Le processus parent attend la fin du processus enfant en appelant ces fonctions et obtient son statut de sortie, libérant ainsi les ressources occupées par le processus enfant.pid_t wait(int *stat_loc);
pid_t waitpid(pid_t pid, int *stat_loc, int options);
pid_t wait3(int *status, int options, struct rusage *rusage);
pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage);
La valeur de retour est le numéro du processus enfant.
stat_loc
Les informations sur la fin du processus enfant sont-elles :
a) Si elle est terminée normalement, la macro WIFEXITED(stat_loc)
Renvoie vrai, macroWEXITSTATUS(stat_loc)
Le statut de cessation d'emploi peut être obtenu ;
b) Si elle se termine anormalement, la macro WTERMSIG(stat_loc)
Obtient le signal pour terminer le processus.
Si le processus parent est occupé, vous pouvez capturer SIGCHLD
Signal, appelé dans la fonction de traitement du signalwait()
/waitpid()
。
[Envoyer des signaux entre les processus](##1.5 Envoyer des signaux)
Dans un programme de service multi-processus, si le sous-processus reçoit un signal de sortie, le sous-processus se terminera tout seul.
Si le processus parent reçoit un signal de sortie, il doit envoyer des signaux de sortie à tous les processus enfants, puis se quitter.
Les multi-threads partagent l'espace d'adressage d'un processus,Si plusieurs threads doivent accéder à la même mémoire, utilisez simplement des variables globales.。
Dans plusieurs processus, l'espace d'adressage de chaque processus est indépendant et non partagé.Si plusieurs processus doivent accéder à la même mémoire, les variables globales ne peuvent pas être utilisées, seule la mémoire partagée peut être utilisée.。
La mémoire partagée permet à plusieurs processus (aucune relation de sang entre les processus n'est requise) d'accéder au même espace mémoire. C'est le moyen le plus efficace de partager et de transférer des données entre plusieurs processus. Les processus peuvent connecter la mémoire partagée à leur propre espace d'adressage. Si un processus modifie les données de la mémoire partagée, les données lues par d'autres processus changeront également.
La mémoire partagée ne fournit pas de mécanisme de verrouillage, c'est-à-dire que lorsqu'un processus lit/écrit la mémoire partagée, elle n'empêche pas les autres processus de la lire/écrire.Si vous souhaitez verrouiller la lecture/écriture de la mémoire partagée, vous pouvez utiliser un sémaphore . Linux fournit un ensemble de fonctions pour exploiter la mémoire partagée.
Cette fonction est utilisée pour créer/acquérir de la mémoire partagée.
int shmget(key_t key, size_t size, int shmflg);
typedef unsigned int key_t
), généralement en hexadécimal, par exemple 0x5005
, les clés des différentes mémoires partagées ne peuvent pas être les mêmes.0666|IPC_CREAT
Indique que si la mémoire partagée n'existe pas, créez-la.utiliser ipcs -m
Vous pouvez afficher la mémoire partagée du système, notamment : la clé, l'identifiant de la mémoire partagée (shmid), le propriétaire, les autorisations (perms) et la taille (octets).
utiliser ipcrm -m 共享内存id
La mémoire partagée peut être supprimée manuellement comme suit :
Remarque : Les conteneurs ne peuvent pas être utilisés pour les types de données en mémoire partagée, seuls les types de données de base peuvent être utilisés.
Cette fonction est utilisée pour connecter la mémoire partagée à l'espace d'adressage du processus en cours.
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmget()
L'identifiant de la mémoire partagée renvoyé par la fonction.Renvoie l'adresse de départ de la mémoire partagée lorsque l'appel réussit et revient en cas d'échec. (void *)-1
。
Cette fonction permet de détacher la mémoire partagée du processus en cours, ce qui équivaut à shmat()
L’opération inverse d’une fonction.
int shmdt(const void *shmaddr);
shmat()
L'adresse renvoyée par la fonction.Renvoie 0 si l'appel réussit et -1 s'il échoue.
Cette fonction est utilisée pour faire fonctionner la mémoire partagée. L'opération la plus couramment utilisée consiste à supprimer la mémoire partagée.
int shmctl(int shmid, int command, struct shmid_ds *buf);
shmget()
L'identifiant de la mémoire partagée renvoyé par la fonction.IPC_RMID
。Renvoie 0 si l'appel réussit et -1 s'il échoue.
Attention, utilisez root
La mémoire partagée créée ne peut pas être supprimée par les utilisateurs ordinaires, quelles que soient les autorisations créées.
Renvoie 0 si l'appel réussit et -1 s'il échoue.
Cette fonction est utilisée pour faire fonctionner la mémoire partagée. L'opération la plus couramment utilisée consiste à supprimer la mémoire partagée.
int shmctl(int shmid, int command, struct shmid_ds *buf);
shmget()
L'identifiant de la mémoire partagée renvoyé par la fonction.IPC_RMID
。Renvoie 0 si l'appel réussit et -1 s'il échoue.
Attention, utilisez root
La mémoire partagée créée ne peut pas être supprimée par les utilisateurs ordinaires, quelles que soient les autorisations créées.
[Les images de liens externes sont en cours de transfert...(img-v6qW3XRA-1720711279572)]
[Les images de liens externes sont en cours de transfert...(img-CG0tGAne-1720711279572)]