Maison > Article > Tutoriel système > En tant qu'ingénieur de développement embarqué, vous devez connaître le mécanisme de synchronisation du noyau Linux
La synchronisation est l'interaction entre les processus et entre les processus et les ressources système. Étant donné que le noyau Linux utilise le multitâche, il doit exister un mécanisme de synchronisation entre plusieurs processus pour assurer la coordination.
Il existe de nombreux mécanismes de synchronisation dans le noyau Linux. Aujourd'hui, nous allons nous concentrer sur les mécanismes asynchrones et synchrones du noyau, en nous concentrant sur le mécanisme asynchrone du noyau. Le mécanisme asynchrone du noyau est divisé en deux types : l'un est le mécanisme de synchronisation de la couche application, c'est-à-dire la communication entre les threads de la couche application ;
Lorsqu'un thread entre dans l'état du noyau, il peut communiquer directement avec le noyau. Il y a deux threads dans le noyau : l'un est le thread A. Une fois entré dans l'état du noyau, il communiquera directement avec le noyau et lui dira quoi faire. Une fois terminé, il en informera le noyau. (Nous appelons cette opération semi) Lorsqu'un thread entre dans l'état du noyau, il communiquera d'abord une fois avec le noyau, puis il pourra être exécuté directement.
Le mécanisme de synchronisation dans le noyau est essentiellement un mécanisme de communication entre les threads, et la communication entre eux est réalisée via le mécanisme de synchronisation.
Afin de garantir l'exactitude et la cohérence du système, le noyau Linux utilisera des files d'attente de blocage pour gérer la communication inter-processus pendant la communication inter-processus. Une file d'attente bloquante signifie qu'un élément dans la file d'attente des messages est créé lorsqu'un message est envoyé, mais que tous les messages ne seront pas envoyés. Ce n'est que lorsque la file d'attente d'un certain message est pleine qu'il sera envoyé. S'il n'y a pas de message dans la file d'attente du destinataire, la notification sera reçue. S'il y a un message dans la file d'attente du destinataire, aucune notification ne sera reçue.
Dans le noyau, la file d'attente de blocage est abstraite, c'est-à-dire que lorsqu'un processus envoie un message, il est bloqué. Par conséquent, la file d’attente de blocage est en fait un mécanisme de synchronisation. La file d'attente de blocage crée un nouvel objet via une fonction spécifique, qui contient un pointeur de file d'attente (Push/Pop). Lorsque la file d'attente est pleine, le système utilisera l'objet pointé par le pointeur de la file d'attente comme thread du premier processus à émettre une notification. Autrement dit, le processus sera averti avant de pouvoir continuer à exécuter ses tâches.
Les sémaphores peuvent être utilisés pour envoyer ou recevoir des messages. Lorsqu'un processus possède un sémaphore, cela signifie qu'il possède déjà son propre sémaphore, qui est une variable privée qui lui est propre. Cette variable privée ne peut pas être obtenue par d'autres processus. Les sémaphores sont utilisés pour représenter le nombre de sémaphores possédés par un processus. Lorsque ce processus possède le sémaphore, il peut envoyer des messages à d'autres processus. Cette variable privée ne peut être utilisée que par ce processus lui-même et ne peut pas être appliquée aux processus d'autres processus.
Lorsqu'un thread possède son propre sémaphore, il peut communiquer avec d'autres threads via des variables partagées. Les variables partagées sont également utilisées dans d'autres threads, et d'autres threads utilisent des variables partagées pour communiquer avec eux-mêmes.
Mutex est principalement destiné aux ressources système. Les mutex dans le noyau Linux peuvent être divisés en deux types : les ressources partagées et les ressources mutex globales.
Les ressources partagées sont partagées entre les processus. Par exemple, si un processus a plusieurs threads, chaque thread peut accéder à cet espace mémoire partagé. Les ressources globales mutuellement exclusives signifient que les processus et les threads ne peuvent accéder qu'à l'espace mémoire global où ils se trouvent. Dans un système, les mutex peuvent être utilisés pour permettre à plusieurs processus de s'exécuter en mémoire en même temps. Mais si vous souhaitez implémenter plusieurs processus s'exécutant en même temps, vous devez utiliser un mécanisme de synchronisation pour garantir que tous les processus peuvent s'exécuter dans la même mémoire. À l'aide d'un mutex, un processus ne peut accéder qu'à l'espace mémoire global où il se trouve, mais ne peut pas accéder aux autres espaces mémoire. Mais un mutex présente un gros avantage : il n’y aura pas de blocage de processus.
L'émergence des files d'attente de messages a considérablement élargi la communication inter-processus. Dans le noyau, en plus du mécanisme de synchronisation, il existe un autre mécanisme asynchrone, à savoir la file d'attente des messages. Nous savons tous que le noyau Linux prend en charge les files d'attente de messages. Bien qu'il existe des informations détaillées sur les files d'attente de messages dans le noyau, étant donné que le noyau ne prend pas en charge les files d'attente de messages en mode utilisateur, nous devons toujours commencer par la couche application pour comprendre les files d'attente de messages.
Tout d’abord, comprenons ce qu’est une file d’attente de messages ?
La file d'attente de messages est une file d'attente spéciale qui peut répondre aux besoins de synchronisation entre plusieurs threads d'application. Les files d'attente de messages sont utilisées pour fournir une communication asynchrone entre les applications et d'autres processus ou threads. Si nous devons communiquer de manière asynchrone, nous pouvons le faire en utilisant une file d'attente de messages. Par exemple, lorsque nous appelons la fonction clear(), nous pouvons directement utiliser une file d'attente de messages enregistrée.
Alors comment créer une file d'attente de messages ? Lorsque nous utilisons ext2.json, nous pouvons créer une file d'attente de messages à l'aide de la commande sémaphore dans JAR.json.clear().
Dans la mémoire partagée, nous utilisons des verrous partagés, mais comme les verrous partagés partagent la mémoire avec un certain processus, lorsque vous souhaitez acquérir un verrou partagé, vous devez le demander à d'autres processus.
Comme dans l'exemple ci-dessus, nous accédons à la mémoire partagée via le mot-clé volatile. Pour le moment, vous ne demandez pas à d’autres processus, donc lorsque vous souhaitez acquérir ce verrou partagé, il vous suffit de demander à d’autres processus. Cela évite la concurrence entre les deux processus et réalise la synchronisation des données.
Puisqu'un verrou partagé partage la mémoire avec un processus, vous devez demander au processus d'accéder à son adresse. La solution la plus simple à cette situation consiste à utiliser un pool de threads.
Il existe un objet appelé « octet » dans le pool de threads, qui est également un verrou partagé. Lorsque vous souhaitez acquérir ce verrou, il vous suffit d'envoyer une requête à l'objet byte. À ce moment-là, l'objet byte enverra votre requête à la file d'attente du thread. Lorsque le thread recevra la requête, il vous renverra un message de réponse.
Le pool de threads est un très bon outil de gestion de threads. Il permet à plusieurs threads de s'exécuter en même temps et peut également réduire les blocages et les conflits entre les threads. L'une de ses caractéristiques les plus importantes est qu'il peut utiliser efficacement la mémoire du système pour améliorer l'efficacité.
L'utilisation des pools de threads est très simple, il suffit d'allouer les tâches à exécuter aux pools de threads correspondants. Lorsque la tâche à exécuter est affectée au pool de threads correspondant, elle peut être exécutée. Utiliser un pool de threads nous apportera de nombreux avantages :
Deux mécanismes de synchronisation sont présentés ci-dessus, examinons donc le mécanisme de synchronisation dans l'état du noyau. Il existe quatre méthodes de synchronisation dans l'état du noyau :
.Grâce à l'analyse ci-dessus, nous comprenons que la synchronisation est un problème complexe. Comment la synchronisation est-elle effectuée dans l'état du noyau ?
Tout d'abord, il y a trois processus dans l'état du noyau : ces trois processus peuvent accéder aux ressources les uns des autres, et peuvent également se synchroniser lorsque des ressources sont demandées par d'autres processus.
Lorsqu'un processus est bloqué, tous ses processus enfants retireront un processus enfant (ou un autre processus enfant) de la file d'attente et l'ajouteront à la file d'attente de blocage. Lorsque tous les processus enfants sont bloqués, il n’y a aucun processus enfant dans la file d’attente de blocage. À ce stade, les autres processus enfants dans la file d'attente ajouteront le thread actuel à la file d'attente. Ces trois processus ne s'affecteront pas pendant le processus d'attente. Les trois threads peuvent se synchroniser avec d'autres threads en définissant leurs propres priorités.
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!