Partage de technologie

Serveur de réacteur à haute concurrence [moyen]

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

4. Contrôle des processus et synchronisation des processus

1. Signaler

1.1 Concepts de base des signaux

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.killetkillallCommande pour envoyer le signal :

kill -信号的类型 进程编号
killall -信号的类型 进程名
  • 1
  • 2

1.2 Types de signaux

nom du signalvaleur du signalAction de traitement par défautRaison de la signalisation
INSCRIVEZ-VOUS1UNLe terminal se bloque ou le processus de contrôle se termine
Signal d'information2UNInterruption du clavier Ctrl+c
SIGQUIT3CLa touche d'échappement du clavier est enfoncée
SIGILLE4CEnseignement illégal
SIGTRIP (piège à signaux)5Cinstructions de point d'arrêt
SIGABRT6CSignal d'abandon émis par abort(3)
SIGBUS7Cerreur de bus
SIGFPE8Cexception à virgule flottante
Sigkill9UNkill -9 tue le processus, ce signal ne peut pas être capté et ignoré
SIGUSR110UNSignal défini par l'utilisateur 1
SIGSEGV11CRéférence mémoire invalide (tableau hors limites, opération de pointeur nul)
SIGUSR212UNSignal défini par l'utilisateur 2
Tuyau SIG13UNÉcrire des données dans un tube sans processus de lecture
SIGALRM14UNSignal de réveil, signal envoyé par la fonction alarm()
TERME DE SIG15UNSignal de terminaison, le signal envoyé par défaut
SIGSTKFLT16UNerreur de pile
SIGCHLD17BÉmis à la fin du processus enfant
SIGCONT18DReprendre un processus arrêté
ARRÊT SIGS19DArrêter le processus
SIGTSTP20DTerminal appuyer sur la touche stop
SIGTTIN21DDemandes de processus en arrière-plan pour lire le terminal
SIGTTOU22DLe processus en arrière-plan demande à écrire sur le terminal
SIGURG23BDétection des conditions d'urgence (prises)
Processeur SIGX24CLimite de temps CPU dépassée
SIGXFSZ25CLimite de taille de fichier dépassée
SIGNALRM26UNsignal d'horloge virtuelle
SIGPROF27UNAnalyser les signaux d'horloge
TREUIL SIG28BModifications de la taille de la fenêtre
Sondage SIG29BInterrogation (Sys V)
SIGPWR30UNpanne d'électricité
SIGSYS31CAppel 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.

1.3 Traitement du signal

Il existe trois manières pour les processus de gérer les signaux :

  1. L'opération par défaut du système est utilisée pour gérer ce signal. L'opération par défaut de la plupart des signaux consiste à terminer le processus.
  2. Définissez la fonction de traitement des interruptions. Après avoir reçu le signal, la fonction le gérera.
  3. Ignorez un signal et ne faites rien avec le signal comme si cela ne s'était jamais produit.

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);
  • 1
  • 2
  • 3
  • 4

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é.
  1. SIG_DFL La macro :SIG_DFL représente la méthode de traitement du signal par défaut.utiliserSIG_DFLcommesignalLe 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.
  2. SIG_IGN La macro :SIG_IGN signifie ignorer le signal.utiliserSIG_IGNcommesignal 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.
  3. SIG_ERR:SIG_ERR Les macros sont utilisées pour indiquer les erreurs.ce n'est pas commesignalLe 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é.sisignalSi l'appel à la fonction échoue, elle renverraSIG_ERR .Ceci est généralement utilisé pour détecter et traitersignalErreur dans l'appel de fonction.

image-20240709113614147

image-20240709113230874

image-20240709113240944

1.4 A quoi servent les signaux ?

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.

image-20240709135336848

1.5 Envoi de signaux

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);
  • 1

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 :

  1. pid > 0 Transmettez le signal au processus commepid processus.
  2. 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.
  3. pid < -1 Transmettez le signal à l'ID du groupe de processus de|pid| de tous les processus.
  4. pid = -1 Transmet le signal à tous les processus autorisés à envoyer le signal, mais pas au processus qui a envoyé le signal.

2. Fin du processus

Il existe 8 façons de terminer un processus, dont 5 sont des terminaisons normales, à savoir :

  1. exister main() Pour les fonctionsreturn retour;
  2. Appelé dans n'importe quelle fonction exit() fonction;
  3. Appelé dans n'importe quelle fonction _exit() ou_Exit() fonction;
  4. Le dernier thread démarre à partir de sa routine de démarrage (fonction principale du thread) avec return retour;
  5. Appelé dans le dernier fil pthread_exit() retour;

Il existe trois manières de terminer anormalement :

  1. transfert abort() fonction d'abandon ;
  2. Un signal est reçu ;
  3. Le dernier fil répond à la demande d'annulation.

2.1 Statut de fin du processus

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 $?
  • 1

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);
  • 1
  • 2
  • 3

status L’état de fin du processus.

image-20240709143530327

image-20240709143615950

2.2 Problème de libération des ressources

  • 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é.

2.3 Fonction de terminaison du processus

Le processus est disponible atexit() L'enregistrement des fonctions termine les fonctions (jusqu'à 32), ces fonctions serontexit() Appelé automatiquement.

int atexit(void (*function)(void));
  • 1

exit() L'ordre dans lequel les fonctions de terminaison sont appelées est inversé à partir du moment de l'inscription.

image-20240709143824286

image-20240709143830549

3. Appelez le programme exécutable

3.1 Fonction système()

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);
  • 1

system()La valeur de retour de la fonction est plus gênante.

  1. Si le programme exécuté n'existe pas,system()La fonction renvoie une valeur différente de zéro ;
  2. Si l'exécution du programme est réussie et que l'état d'exécution du programme exécuté est 0,system()La fonction renvoie 0 ;
  3. Si l'exécution du programme réussit et que l'état de fin du programme exécuté n'est pas 0,system()La fonction renvoie une valeur différente de zéro.

3.2 Famille de fonctions d'exécution

execLes familles de fonctions offrent un autre moyen d'appeler des programmes (binaires ou scripts shell) au sein d'un processus.

execLa 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[]);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Avis

  1. Si l'exécution du programme échoue, -1 est renvoyé directement et la raison de l'échec est stockée danserrnomilieu.
  2. Le numéro de processus du nouveau processus est le même que celui du processus d'origine, mais le nouveau processus remplace le segment de code, le segment de données et la pile du processus d'origine.
  3. Si l'exécution réussit, la fonction ne sera pas renvoyée lorsqu'elle est appelée avec succès dans le programme principal.execAprès cela, le programme appelé remplacera le programme appelant, c'est-à-direexecAucun code après la fonction ne sera exécuté.
  4. Dans le développement réel, le plus couramment utilisé estexecl()etexecv(), d'autres sont rarement utilisés.

4. Créer un processus

4.1 Processus Linux 0, 1 et 2

Tous les processus de l'ensemble du système Linux sont dans une structure arborescente.

  • **Le processus n°0 (processus système)** est l'ancêtre de tous les processus. Il a créé les processus n°1 et n°2.
  • **Le processus n° 1 (systemd)** est responsable de l'initialisation du noyau et de la configuration du système.
  • **Le processus n° 2 (kthreadd)** est responsable de la planification et de la gestion de tous les threads du noyau.

utiliserpstreeVous pouvez visualiser l'arborescence des processus avec la commande :

pstree -p 进程编号
  • 1

4.2 Identification du processus

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。
  • 1
  • 2

4.3 Fonction fork()

Un processus existant peut appelerfork()La fonction crée un nouveau processus.

Déclaration de fonction :

pid_t fork(void);
  • 1

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.

image-20240709221535371

image-20240709221546617

4.4 Deux utilisations de fork()

  1. Le processus parent veut se copier, puis le processus parent et le processus enfant exécutent chacun un code différent.Cette utilisation est très courante dans les programmes de service réseau. Le processus parent attend la demande de connexion du client. Lorsque la demande arrive, le processus parent appelle.fork(), laissez le processus enfant gérer ces demandes, pendant que le processus parent continue d'attendre la prochaine demande de connexion.
  2. Le processus veut exécuter un autre programme.Cette utilisation est très courante dans les shells, le processus enfant commence à partir defork()Appelé immédiatement après le retourexec

4.5 Fichiers partagés

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.

image-20240709222929369

image-20240709222803641

À ce stade, vous pouvez constater qu’il n’existe que 100 000 lignes de données.

image-20240709222853769

image-20240709223236254

À 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.

4.6 Fonction vfork()

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 estexecUn 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 enfantexecouexitEnsuite, le processus parent reprend ses opérations.

5. Processus zombie

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.

5.1 Causes des processus zombies

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.

5.2 Les méfaits des processus zombies

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.

5.3 Méthodes pour éviter les processus zombies

  1. Gestion du signal SIGCHLD : Lorsque le processus enfant se termine, le noyau enverra le signal SIGCHLD au processus parent.Si le processus parent utilisesignal(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.
  2. utiliserwait()/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);
  • 1
  • 2
  • 3
  • 4

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.

image-20240709230911352

image-20240709231034423

image-20240709231050581

image-20240709231124375

image-20240709231140813

Si le processus parent est occupé, vous pouvez capturer SIGCHLD Signal, appelé dans la fonction de traitement du signalwait()/waitpid()

image-20240709231439475

image-20240709231422927

6. Processus et signaux multiples

[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.

image-20240711222919564

image-20240711222900141

image-20240711223111481

7. Mémoire partagée

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.

7.1 Fonction shmget

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);
  • 1
  • clé La valeur clé de la mémoire partagée est un entier (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.
  • taille Taille de la mémoire partagée, en octets.
  • shmflg Les autorisations d'accès à la mémoire partagée sont les mêmes que les autorisations pour les fichiers, par exemple0666|IPC_CREAT Indique que si la mémoire partagée n'existe pas, créez-la.
  • valeur de retour: Renvoie l'identifiant de la mémoire partagée (un entier supérieur à 0) en cas de succès, -1 en cas d'échec (le système a une mémoire insuffisante et aucune autorisation).

image-20240711224223200

image-20240711224212293

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 :

image-20240711225202860

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.

7.2 Fonction shmat

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);
  • 1
  • shmideee Dépend deshmget() L'identifiant de la mémoire partagée renvoyé par la fonction.
  • smaddr Spécifiez l'emplacement de l'adresse où la mémoire partagée est connectée au processus en cours. Remplissez généralement 0 pour permettre au système de sélectionner l'adresse de la mémoire partagée.
  • shmflg Bit de drapeau, généralement rempli de 0.

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

7.3 Fonction shmdt

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);
  • 1
  • smaddr shmat() L'adresse renvoyée par la fonction.

Renvoie 0 si l'appel réussit et -1 s'il échoue.

7.4 Fonction shmctl

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);
  • 1
  • shmideee shmget() L'identifiant de la mémoire partagée renvoyé par la fonction.
  • commandee Instructions pour utiliser la mémoire partagée Si vous souhaitez supprimer la mémoire partagée, remplissez-la.IPC_RMID
  • buf L'adresse de la structure de données qui exploite la mémoire partagée. Si vous souhaitez supprimer la mémoire partagée, remplissez 0.

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.

image-20240711230653886

image-20240711230522921

7.5 File d'attente circulaire

7.6 File d'attente circulaire basée sur la mémoire partagée

Renvoie 0 si l'appel réussit et -1 s'il échoue.

7.4 Fonction shmctl

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);
  • 1
  • shmideee shmget() L'identifiant de la mémoire partagée renvoyé par la fonction.
  • commandee Instructions pour utiliser la mémoire partagée Si vous souhaitez supprimer la mémoire partagée, remplissez-la.IPC_RMID
  • buf L'adresse de la structure de données qui exploite la mémoire partagée. Si vous souhaitez supprimer la mémoire partagée, remplissez 0.

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)]Le transfert de l'image du lien externe a échoué. Le site source peut disposer d'un mécanisme anti-sangsue. Il est recommandé de sauvegarder l'image et de la télécharger directement.
Le transfert de l'image du lien externe a échoué. Le site source peut disposer d'un mécanisme anti-sangsue. Il est recommandé de sauvegarder l'image et de la télécharger directement.
Le transfert de l'image du lien externe a échoué. Le site source peut disposer d'un mécanisme anti-sangsue. Il est recommandé de sauvegarder l'image et de la télécharger directement.

7.5 File d'attente circulaire

7.6 File d'attente circulaire basée sur la mémoire partagée