Système d'exploitation 2 - Description et contrôle du processus

Cette série de blogs se concentre sur le tri du contenu de base du cours de système d'exploitation de l'Université de Shenzhen, et la bibliographie "Système d'exploitation informatique" (si vous avez des questions, veuillez discuter et signaler dans la zone de commentaires, ou contactez-moi directement par message privé).


synopsis

Ce blog présente principalement les connaissances pertinentes de la description et du contrôle du processus dans le chapitre 2 du système d'exploitation.

Table des matières

1. Diagramme des précurseurs et exécution du programme

1. Exécution du programme en séquence

2. Carte des précurseurs

3. Exécution simultanée de programmes

2. Description du processus

1. Définition et caractéristiques

2. Statut du processus

2.1 État de base

2.2 Supplément de statut

3. Bloc de contrôle de processus (PCB)

3.1 Contient des informations

3.2 Organisation du PCB

3. Contrôle de processus 

1. Noyau du système d'exploitation

1.1 Fonction d'assistance

1.2 Fonction de gestion des ressources

2. Création de processus

3. Processus terminé

4. Blocage et réveil du processus

4.1 Processus de blocage du processus

4.2 Processus de réveil du processus

5. Suspension et activation du processus

5.1 Le processus se bloque

5.2 Activation du processus

6. Les primitives de contrôle de processus complètent Linux/UNIX

4. Synchronisation des processus

1. Deux contraintes

2. Ressources critiques - problème "producteur-consommateur"

3. Section critique

4. Mécanisme de synchronisation du programme

5. Mécanisme de sémaphore

5.1 Sémaphore entier

5.2 Sémaphores enregistrés

5.3 Types de sémaphores

5.4 Sémaphore de type ET

5.5 Collecte de quantité de signal

6. Application du sémaphore

6.1 Utiliser des sémaphores pour réaliser un processus d'exclusion mutuelle

6.2 Utiliser des sémaphores pour réaliser la relation de prédécesseur

6.3 Utilisation du mécanisme de sémaphore pour réaliser la synchronisation des processus

7. Problème de synchronisation de processus classique

7.1 Problème producteur-consommateur

7.2 Problèmes de gestion de la salle de lecture (variantes production et élimination)

7.3 Le problème des philosophes de la restauration

7.4 Le problème lecteur-écrivain

À faire : les écrivains d'abord

7.5 Traverser le problème du pont à une planche (variantes de lecture et d'écriture)

8. Mécanisme de surveillance

8.1 Définition

8.2 Exemple (problème producteur-consommateur)

Cinq, processus de communication

1. Type de communication de processus

1.1 Système de mémoire partagée

1.2 Système de messagerie

1.3 Communication par canalisation (tuyau)

1.4 Système client-serveur

2. Mise en œuvre de la communication par passage de messages

2.1 Communication directe - Messagerie directe

2.2 Communication indirecte - Communication par boîte vocale

3. Plusieurs problèmes dans la mise en œuvre du système de livraison de messages

3.1 Lien de communication

3.2 Format du message

3.3 Méthode de synchronisation de processus

3.4 Utilisation de la transmission de messages pour parvenir à l'exclusion mutuelle

4. Exemple de système de messagerie directe

4.1 Mécanisme de communication de file d'attente de tampon de messages

4.2 Envoyer des primitives

4.3 Recevoir des primitives

Six, fil

7. Quelques exemples


Commençons par un petit exemple :

Nous savons tous que le processeur bascule constamment entre les processus. Donc, pour un processus, dans laquelle des situations suivantes, il doit obtenir le processeur ?

A. Le processus n'est pas terminé

B. Le processus attend la fin d'une opération d'E/S

C. Le processus effectue une opération complexe

D. Aucune des réponses ci-dessus

Résumé : Dans le système d'exploitation, les ressources CPU sont allouées par le planificateur. Le planificateur détermine quel processus a accès au CPU. Lorsque le système a plusieurs processus en cours d'exécution, le planificateur alloue du temps CPU à ces processus et les laisse occuper le CPU à tour de rôle pour terminer leur travail.

R : Le processus n'est pas terminé. S'il est dans l'état bloqué, il n'occupera pas le processeur. Il attendra d'obtenir le processeur lorsqu'il sera réveillé et entrera dans l'état prêt. En même temps, le système d'exploitation a également le concept de priorité. La haute priorité obtient le processeur en premier.

B : Le processus attend la fin d'une opération d'E/S, et il peut également abandonner activement le processeur afin que d'autres processus prêts puissent obtenir le processeur (généralement en bloquant et en attendant),

Astuces : L'état du CPU qui peut être obtenu est le suivant : Lorsqu'un processus envoie une demande d'E/S, si le périphérique n'est pas prêt, le processus peut être suspendu par le système d'exploitation et attendre que l'E/S se termine À ce stade, le processus est appelé un état bloqué. Dans l'état bloqué, le processus abandonne temporairement la CPU jusqu'à ce que l'opération d'E/S soit terminée et que le processus soit prêt à s'exécuter à nouveau.

C : Le processus effectue une opération complexe, comme ci-dessus, en fonction de la priorité du programme et de la politique d'ordonnancement du système d'exploitation.

1. Diagramme des précurseurs et exécution du programme

1. Exécution du programme en séquence

Ce n'est qu'après l'exécution de l'opération précédente (bloc) que l'opération suivante peut être exécutée.

A ce moment, le programme monopolise le processeur , et ses caractéristiques incluent : la séquentialité , la fermeture (chaque ressource n'est contrôlée que par le programme pendant l'exécution), et la reproductibilité

2. Carte des précurseurs

Le graphe prédécesseur est un graphe acyclique dirigé , qui est noté DAG, et est utilisé pour décrire la relation d'exécution entre les processus . Chaque nœud du graphique peut être utilisé pour décrire un segment ou un processus de programme, voire une instruction, et a en même temps un poids, qui est utilisé pour représenter la quantité de programme contenue dans le nœud ou le temps d'exécution du nœud .

Astuces : Pi→Pj, Pi est appelé le prédécesseur direct de Pj, et Pj est dit le successeur direct de Pi. Il n'y a pas de prédécesseurs ou de successeurs, c'est-à-dire des nœuds de démarrage/d'arrêt.

Pour le graphe de prédécesseur de l'exemple, il existe les relations de prédécesseur suivantes :

3. Exécution simultanée de programmes

Bien que l'exécution séquentielle du programme soit pratique, le taux d'utilisation des ressources système est très faible, de sorte que la technologie de multi-programmation est introduite pour qu'il s'exécute simultanément.

Conseils : L'exécution simultanée n'est possible qu'entre des programmes qui n'ont pas de relation de prédécesseur

Regardons un exemple :

Pour l'exécution séquentielle dans la figure ci-dessus, il est facile de trouver qu'il y a Ii→Ci→Pi (généralisé à l'entrée, au calcul et à l'impression d'un travail), mais en fait, il peut être exécuté simultanément pour optimiser l'efficacité, comme suit (la partie pouvant être concurrente est marquée d'un trait rouge , entre Pi-1 et Ci et Ii+1) :

Prenons un autre exemple :

Pour un bloc avec les quatre instructions suivantes :

 S1 : a∶=x+2 S2 : b∶=y+4 S3 : c∶=a+b S4 : d∶=c+b 

Le schéma précurseur est le suivant :

Après l'introduction de l'exécution simultanée, le débit et l'utilisation des ressources du système sont améliorés , mais ils coopèrent pour accomplir la même tâche et se restreignent , de sorte que certaines nouvelles fonctionnalités apparaissent comme suit : 

Intermittent (des contraintes mutuelles feront que les programmes concurrents auront un modèle d'activité intermittent de " exécution-pause-exécution ")

Perte de fermeture (les ressources système sont modifiées par plusieurs programmes)

Irreproductibilité (le programme est exécuté plusieurs fois dans le même environnement et les mêmes conditions initiales, et les résultats sont différents)

Un exemple est le suivant :

2. Description du processus

Étant donné que le résultat de l'exécution peut ne pas être reproduit lorsque le programme est exécuté simultanément, le concept de "programme" ne peut pas être utilisé pour décrire l'exécution simultanée du programme, donc un nouveau concept - processus doit être introduit pour décrire l'exécution simultanée du programme , et Gérer le processus si nécessaire pour garantir des résultats reproductibles lorsque le processus est exécuté simultanément. 

1. Définition et caractéristiques

Définition de processus : le processus en cours d'exécution d'un programme qui peut être exécuté simultanément sur un ensemble de données - MIT, la première définition

Autres définitions typiques :

(1) Un processus est une exécution d'un programme.  

(2) Un processus est l'activité qui se produit lorsqu'un programme et ses données sont exécutés séquentiellement sur un processeur.

(3) Un processus est un processus dans lequel un programme s'exécute sur un ensemble de données, et c'est une unité indépendante pour l'allocation et la planification des ressources par le système.

Après avoir introduit le concept d'entité de processus, nous pouvons définir un processus dans un système d'exploitation traditionnel comme : "Un processus est le processus en cours d'exécution d'une entité de processus et constitue une unité indépendante permettant au système d'allouer et de planifier des ressources ".

Un processus et un programme sont deux concepts complètement différents. Les caractéristiques d'un processus sont les suivantes :

Dynamique : La dynamique est la caractéristique la plus fondamentale d'un processus, c'est le processus d'exécution du programme, et il a un certain cycle de vie (création, planification, suspension, fin) . Le programme est statique, c'est un ensemble d'instructions ordonnées stockées sur le support.

Concurrence : La concurrence est une caractéristique importante d'un processus, et c'est aussi une caractéristique importante d'un système d'exploitation. La simultanéité signifie que plusieurs entités de processus coexistent en mémoire et peuvent s'exécuter simultanément pendant un certain temps. Le programme ne peut pas être exécuté simultanément.

Indépendance : Un processus est une unité de base qui peut fonctionner de manière indépendante , c'est-à-dire une unité qui obtient des ressources et des horaires de manière indépendante, et le programme ne participe pas à l'opération en tant qu'unité indépendante.

Asynchronie : les processus avancent à des vitesses indépendantes et imprévisibles , c'est-à-dire que les processus sont exécutés de manière asynchrone. C'est cette caractéristique qui conduira à la non-reproductibilité de l'exécution du programme. Par conséquent, le système d'exploitation doit prendre certaines mesures pour limiter la progression. de chaque processus Séquence pour assurer une coordination normale entre les programmes.

Caractéristiques structurelles : Structurellement, l'entité de processus se compose de trois parties : segment de programme, segment de données et bloc de contrôle de processus (PCB) , appelé "image de processus" sous UNIX.

Une instance en cours d'exécution simultanée est la suivante :

2. Statut du processus

2.1 État de base

Introduisez d'abord les trois états de base du processus

État d'exécution/état d'exécution (Running) : un processus est en cours d'exécution sur le processeur (CPU).

État prêt (Ready) : un processus a obtenu toutes les ressources requises, à l'exception du processeur (CPU), et peut s'exécuter après avoir obtenu le processeur.

État bloqué (bloqué) : (également appelé état suspendu, état d'attente) : un processus attend qu'un certain événement se produise (comme une demande d'E/S, un échec de l'application de tampon) et s'arrête temporairement. À ce moment, même si le processeur est affecté à Le processus échoue également à s'exécuter.

Les trois états de base et leurs diagrammes de transition sont les suivants :

Regardez ensuite un exemple :

Dans un système avec un seul processeur, les processus du système d'exploitation ont trois états de base : en cours d'exécution, prêt et bloqué. Supposons que 10 processus s'exécutent simultanément dans le système à un certain moment, et lorsque le temps pris par le planificateur est omis :

Quel est le nombre maximum de processus en cours d'exécution dans le système à ce moment ? au moins combien (1 0)

Quel est le nombre maximum de processus du système à l'état prêt à ce moment ? Combien au moins (9 0)

À ce moment, combien de processus sont à l'état bloquant dans le système au maximum ? Nombre minimal (10 0)

Un processeur a au plus un processus à un certain moment. Si c'est 0, les 10 autres processus doivent tous être mis en file d'attente dans chaque file d'attente bloquante. Si le processeur est libre, le planificateur le programmera immédiatement (si le temps occupé par le planificateur est omis, sinon il sera à l'état prêt jusqu'à 10). 

La gestion de l'état de chaque processus dans le système est la suivante :

  • Processus en cours d'exécution : si le système dispose d'un processeur, à tout moment, au plus un processus est en cours d'exécution.
  • Processus à l'état prêt : généralement, les processus à l'état prêt sont disposés dans une file d'attente prête RL selon un certain algorithme (tel que le processus qui vient en premier ou le processus avec une priorité élevée est classé en tête).
  • Processus en état de blocage : les processus en état de blocage sont mis en file d'attente dans la file d'attente de blocage. En raison de différentes raisons d'attente d'événements, la file de blocage est également divisée en plusieurs files d'attente WLi selon les événements.

2.2 Supplément de statut

Selon la gestion de l'état du processus ci-dessus, afin d'améliorer la flexibilité, l'état de création et l'état de terminaison sont généralement introduits .

Dans de nombreux systèmes, les opérations de suspension et d'activation sont souvent introduites pour les besoins du système et des utilisateurs afin d'observer et d'analyser le processus . 

Conseils : La suspension consiste principalement à arrêter le processus, à dépanner le système ou à observer les résultats intermédiaires

3. Bloc de contrôle de processus (PCB)

Afin de permettre à chaque programme (y compris les données) participant à l'exécution simultanée de s'exécuter indépendamment , le système d'exploitation est équipé d'un bloc de contrôle de structure de données de type enregistrement spécial (PCB), et le système utilise PCB pour décrire la situation de base et activité processus du processus . En d'autres termes, le système d'exploitation contrôle et gère les processus exécutés simultanément en fonction du PCB .

3.1 Contient des informations

Le PCB contient les informations suivantes :

1) Identifiant de processus        

Un identifiant de processus est utilisé pour identifier de manière unique un processus . Un processus possède généralement deux identifiants :

       (1) Identifiant interne. Dans tous les systèmes d'exploitation, chaque processus reçoit un identifiant numérique unique , qui est généralement un numéro de processus. La définition de l'identifiant interne est principalement destinée à la commodité d'utilisation du système.

       (2) Identifiants externes. Il est fourni par le créateur , généralement composé de lettres et de chiffres , et est souvent utilisé par les utilisateurs (processus) lors de l'accès au processus. Afin de décrire la relation familiale du processus, l'ID de processus parent et l'ID de processus enfant doivent également être définis. En outre, un ID utilisateur peut être défini pour indiquer l'utilisateur propriétaire du processus.

 2) Statut du processeur (CPU)        

Les informations d'état du processeur sont principalement composées du contenu des différents registres du processeur .

Les registres à usage général , également appelés registres visibles par l'utilisateur, sont accessibles par les programmes utilisateur et sont utilisés pour stocker temporairement des informations. Dans la plupart des processeurs, il existe de 8 à 32 registres à usage général, et plus de 100 dans les ordinateurs à structure RISC individuel ;

②Compteur d'instructions , qui stocke l'adresse de la prochaine instruction à laquelle accéder ;

Mot d'état du programme PSW , qui contient des informations d'état, telles que le code de condition, le mode d'exécution, l'indicateur de masque d'interruption, etc. ;

Pointeur de pile utilisateur , ce qui signifie que chaque processus utilisateur est associé à une ou plusieurs piles système, qui sont utilisées pour stocker les paramètres d'appel de processus et système et les adresses d'appel. Le pointeur de pile pointe vers le haut de la pile.

3) Traiter les informations de planification        

Certaines informations liées à la planification des processus et à l'échange de processus sont également stockées dans le PCB , notamment :

①État du processus , indiquant l'état actuel du processus, comme base pour la planification et l'échange de processus ;

②Priorité du processus , un entier décrivant le niveau de priorité du processeur utilisé par le processus, et un processus avec une priorité plus élevée obtiendra le processeur en premier ;

Autres informations requises pour la planification de processus , qui sont liées à l'algorithme de planification de processus adopté, par exemple, la somme du temps pendant lequel le processus a attendu le processeur, la somme du temps pendant lequel le processus a été exécuté, etc. ;

④Événement fait référence à l'événement attendant que le processus passe de l'état d'exécution à l'état de blocage, c'est-à-dire la cause du blocage  .

 4) Informations de contrôle de processus

Les informations de contrôle de processus comprennent :

L'adresse du programme et des données fait référence à la mémoire ou à l'adresse de stockage externe (première) où se trouvent le programme et les données du processus, de sorte que lorsque le processus est programmé pour s'exécuter, son programme et ses données peuvent être trouvés à partir du PCB ;

②Le mécanisme de synchronisation et de communication des processus fait référence aux mécanismes nécessaires pour réaliser la synchronisation des processus et la communication des processus, tels que les pointeurs de file d'attente de messages, les sémaphores, etc., qui peuvent être placés dans le PCB en tout ou en partie ;

③Resource list , une liste qui répertorie toutes les ressources requises par le processus à l'exception du CPU et des ressources qui ont été allouées au processus ;

pointeur de lien , qui donne la première adresse du PCB du processus suivant dans la file d'attente où se trouve le processus en cours (PCB).

3.2 Organisation du PCB

Un système comporte généralement des dizaines voire des milliers de PCBs Pour une gestion efficace, il existe généralement différentes méthodes d'organisation :

  • Mode linéaire : Tous les PCB sont dans une table , et la première adresse de la table est placée dans une zone mémoire dédiée. - Frais généraux simples et faibles, mais chaque recherche doit analyser l'intégralité de la table, ce qui convient à moins de PCB.

  • Méthode de liaison : les circuits imprimés du même processus d'état forment une file d'attente, disposés dans un certain ordre (ordre de priorité ou d'entrée)

  • Méthode d'indexation : Selon différents états du processus, plusieurs tables d'index sont établies, et la première adresse est enregistrée dans l'unité de mémoire dédiée.

3. Contrôle de processus 

Le contrôle de processus est la fonction la plus élémentaire de la gestion de processus, comprenant principalement la création, l'arrêt, le blocage, la transition d'état, etc.

1. Noyau du système d'exploitation

Les systèmes d'exploitation modernes divisent généralement le système d'exploitation en plusieurs couches et définissent différentes fonctions dans différentes couches. Certains modules clés (modules étroitement liés au matériel, aux pilotes et à la fréquence de fonctionnement élevée) seront définis dans la couche logicielle à proximité du matériel, c'est-à-dire le noyau du système d'exploitation.

En conséquence, afin d'éviter que le système d'exploitation et ses données clés ne soient endommagés, l'état de la CPU est divisé en état système et état utilisateur .

  • État du système : état du noyau, privilèges plus élevés, peut exécuter toutes les instructions, accéder aux registres et aux zones de mémoire, état du système d'exploitation traditionnel
  • Etat utilisateur : A l'inverse, état applicatif (cas général)

La plupart des systèmes d'exploitation incluent des fonctions de support et des fonctions de gestion des ressources .

1.1 Fonction d'assistance

Les fonctions de base fournies au système d'exploitation et aux autres modules, les trois fonctions de support de base sont les suivantes :

  • Gestion des interruptions : la base sur laquelle le système d'exploitation fonctionne.
  • Gestion de l'horloge : gestion et contrôle des tranches horaires.
  • Opération primitive : une primitive est un processus dans lequel plusieurs instructions sont utilisées pour exécuter une certaine fonction . C'est une "opération atomique", c'est-à-dire une unité de base indivisible . Elle est exécutée dans l'état du système et ne peut pas être interrompue. .

1.2 Fonction de gestion des ressources

Il comprend généralement trois fonctions : la gestion des processus, la gestion de la mémoire et la gestion des périphériques .

2. Création de processus

Dans le système d'exploitation, un processus (processus parent) est autorisé à créer un autre processus (processus enfant), et ainsi de suite à plusieurs reprises pour former une famille de processus (groupe).

Conseils : Le processus enfant peut hériter des ressources détenues par le processus parent (fichiers ouverts, tampons alloués, etc.), qui doivent être renvoyées lorsqu'elles sont révoquées. Afin d'identifier la relation enfant-parent, une entrée de relation familiale est définie dans le PCB . Windows n'a pas de hiérarchie de processus et tous les processus ont le même statut, mais le processus qui crée un nouveau processus obtient un handle (peut être transmis) et peut contrôler d'autres processus.

Afin de décrire clairement la relation entre les groupes de processus, des graphiques de processus (arbres) sont introduits, comme suit :
 

Il existe quatre catégories typiques d'événements qui provoquent la création de processus :

Création du système : (1) Connexion de l'utilisateur (2) Planification des tâches (3) Fourniture de services

Création d'utilisateur : (4) Demande de candidature

Le processus de création d'un processus est le suivant :

(1) Demandez un PCB vierge.              

(2) Allouer des ressources pour le nouveau processus.

(3) Initialiser le bloc de contrôle de processus.              

(4) Insérez le nouveau processus dans la file d'attente des prêts. Si la file d'attente des processus prêts peut accepter le nouveau processus, insérez le nouveau processus dans la file d'attente des prêts.

3. Processus terminé

Il existe trois catégories typiques d'événements qui provoquent la création de processus :

1) Fin normale   Il y a généralement une instruction ou une information pour dire au système d'exploitation de se terminer, provoquant une interruption.

2) Fin anormale   Au cours de l'exécution du processus, en raison de certaines erreurs et échecs, le processus est forcé de se terminer. Il existe de nombreux événements anormaux de ce type, et les plus courants sont : ① Erreur hors limites. Il s'agit de la zone de stockage accessible par le programme, qui a dépassé la zone du processus ; ② Erreur de protection. Le processus essaie d'accéder à une ressource ou à un fichier qui n'est pas autorisé, ou d'y accéder de manière inappropriée, par exemple, le processus essaie d'écrire un fichier en lecture seule ; ③ Instruction illégale. Le programme a tenté d'exécuter une instruction qui n'existe pas. La raison de cette erreur peut être que le programme est transféré par erreur dans la zone de données et que les données sont considérées comme une instruction ; ④ L'instruction privilégiée est erronée. Le processus utilisateur essaie d'exécuter une instruction que seul le système d'exploitation est autorisé à exécuter ; ⑤ L'opération expire. Le temps d'exécution du processus dépasse la valeur maximale spécifiée ; ⑥ Attente du délai d'attente. Le temps d'attente du processus pour un événement dépasse la valeur maximale spécifiée ; ⑦ Erreur d'opération arithmétique. Le processus essaie d'effectuer une opération interdite, par exemple, diviser par 0 ; ⑧ Échec d'E/S. Cela signifie qu'une erreur s'est produite pendant les E/S, etc.

3) L'intervention externe   fait référence à la fin du processus en raison de demandes externes. Ces interventions sont : ① Intervention de l'opérateur ou du système d'exploitation. Pour une raison quelconque, par exemple, un blocage se produit, l'opérateur ou le système d'exploitation met fin au processus ; ② demande de processus parent. Étant donné que le processus parent a le droit de terminer n'importe lequel de ses processus descendants, le système terminera le processus lorsque le processus parent fera une demande ; ③ Le processus parent se termine. Lorsque le processus parent se termine, le système d'exploitation met également fin à tous ses descendants.

Le processus de terminaison du processus est le suivant :

(1) En fonction de l'identifiant du processus terminé, récupérez le PCB du processus dans la collection de PCB et lisez l'état du processus à partir de celui-ci .       

(2) Si le processus terminé est dans l'état d'exécution, l'exécution du processus doit être terminée immédiatement et l'indicateur de planification doit être défini sur true , qui est utilisé pour indiquer que le processus doit être replanifié après avoir été terminé.      

(3) Si le processus a des processus descendants, tous les processus descendants doivent également être terminés pour éviter qu'ils ne deviennent des processus incontrôlables.      

(4) Renvoyer toutes les ressources détenues par le processus terminé à son processus parent ou au système.      

(5) Supprimez le processus terminé (son PCB) de la file d'attente (ou de la liste liée) et attendez que d'autres programmes collectent des informations.

4. Blocage et réveil du processus

Il y a quatre événements typiques qui provoquent le blocage et le réveil d'un processus : 1) Demander un service système 2) Démarrer un type d'opération 3) De nouvelles données ne sont pas arrivées 4) Aucune nouvelle tâche à effectuer

4.1 Processus de blocage du processus

Le processus en cours d'exécution, lorsqu'il trouve l'un des événements ci-dessus, ne peut pas continuer à s'exécuter, donc le processus se bloque en appelant le bloc primitif de blocage (actif). L'exécution du processus doit être arrêtée immédiatement, l'état actuel dans le bloc de contrôle du processus doit être modifié de "exécution" à blocage et inséré dans la file d'attente de blocage. Si plusieurs files d'attente de blocage bloquées par différents événements sont définies dans le système, ce processus doit être inséré dans la file d'attente de blocage (en attente) avec le même événement. Enfin, passez au planificateur pour la replanification, affectez le processeur à un autre processus prêt et basculez, c'est-à-dire conservez l'état du processeur du processus bloqué (dans le PCB), puis appuyez sur le processeur dans le PCB du nouveau processus. state définit l'environnement du CPU.

4.2 Processus de réveil du processus

Lorsque l'événement attendu par le processus bloqué se produit, tel que l'achèvement des E/S ou l'arrivée des données attendues, la primitive de réveil est appelée par le processus concerné (par exemple, le processus qui a utilisé et libéré le périphérique d'E/S ) , qui réveille le processus en attente de l'événement. Le processus de réveil de l'exécution primitive est le suivant : supprimez d'abord le processus bloqué de la file d'attente de blocage en attente de l'événement, modifiez l'état actuel de son PCB de bloqué à prêt, puis insérez le PCB dans la file d'attente prête.

5. Suspension et activation du processus

5.1 Le processus se bloque

Les événements qui provoquent un blocage sont les suivants : (1) demande de l'utilisateur final, (2) demande de processus parent, (3) besoin d'ajustement de charge, (4) besoin du système d'exploitation, (5) besoin d'échange

Lorsqu'un événement entraînant la suspension du processus se produit, le système utilise la primitive de suspension suspend pour suspendre le processus spécifié ou le processus à l'état bloqué. Le processus d'exécution de la primitive de suspension est le suivant : vérifiez d'abord l'état du processus suspendu, actif prêt -> statique prêt ; blocage actif -> blocage statique. Afin de faciliter l'examen du fonctionnement du processus par l'utilisateur ou le processus parent, le PCB du processus est copié dans une zone de mémoire spécifiée. Enfin, si le processus suspendu est en cours d'exécution, tournez-vous vers le planificateur pour le replanifier.

5.2 Activation du processus

Lorsqu'un événement pour activer un processus se produit, le système utilisera la primitive d'activation active pour activer le processus spécifié. La primitive d'activation transfère d'abord le processus du stockage externe vers la mémoire interne, vérifie l'état actuel du processus, statique prêt -> actif prêt ; blocage statique -> blocage actif. Si la stratégie d'ordonnancement préemptif est adoptée, chaque fois qu'un nouveau processus entre dans la file d'attente des prêts, il convient de vérifier si une replanification est nécessaire, c'est-à-dire que l'ordonnanceur comparera la priorité du processus activé avec le processus en cours, et si la priorité du processus le processus activé est Si le niveau est inférieur, il n'est pas nécessaire de replanifier, sinon le processus en cours est immédiatement privé de son exécution et le processeur est alloué au processus nouvellement activé. 

Prenons deux exemples :

Pour changer le processus de prêt actif à prêt statique, la primitive __⑴__ doit être utilisée ; pour changer le processus de l'état d'exécution à l'état bloqué, la primitive __⑵__ doit être utilisée ; pour changer le processus de statique prêt à prêt actif, la primitive Utiliser la primitive __⑶__ ; passer de l'état bloqué à l'état prêt à l'aide de la primitive __⑷__.

⑴:suspendre

⑵:bloquer

⑶:actif

⑷:réveil

Le processus en cours d'exécution est suspendu en raison de l'épuisement de la tranche de temps. À ce moment, le processus doit passer de l'état d'exécution à l'état __⑴__ ; le processus dans l'état de blocage statique doit passer à l'état __⑵__ après que le processus attend la événement à se produire ; si Lorsque le processus est dans l'état d'exécution, il doit être mis en pause à la demande du terminal pour étudier son fonctionnement. A ce moment, le processus doit passer à l'état __⑶__. Si le processus est déjà dans l'état bloqué état, il devrait passer à l'état __⑷__ à ce moment.

⑴ : Activité prête

⑵ : prêt statique

⑶ : prêt statique

⑷ : Blocage statique

6. Les primitives de contrôle de processus complètent Linux/UNIX

1. fork : crée un nouveau processus enfant pid=int fork()

2.exec : appel système

3.exit : l'exécution du processus se termine

4.wait : attendez que le processus enfant se suspende ou se termine

L'exemple de langage C pour créer un processus enfant est le suivant :

#include <stdio.h>
void main()
{ int pid;
   pid=fork();  /* fork child process */
   if (pid<0){ fprintf(stderr, “Fork Failed”);   exit(-1); 
                   }
   else if (pid==0) { execlp(“/bin/ls”,”ls”,NULL); 
                              }  /* child process */
           else { wait(NULL);
                      printf(“child Complete”);
                      exit(0);
                    } /*parent process */
}

Description du programme : ce programme décrit la situation dans laquelle deux processus s'exécutent simultanément après que le processus principal a créé un sous-programme.      

Le processus principal est un processus avant l'exécution de l'appel système fork. Après l'exécution de l'appel système fork, un processus enfant avec le même environnement que le processus d'origine est ajouté au système. Ils exécutent le même programme après l'instruction fork dans le Le processus parent et le processus enfant ont tous deux leur propre pid variable, mais leurs valeurs sont différentes , c'est la valeur de retour après l'appel de fork, le pid du processus parent est une valeur supérieure à 0, il représente le identifiant du processus enfant nouvellement créé, et le pid du processus enfant est 0 . De cette manière, les processus parent et enfant exécutent le même programme, mais exécutent des segments de programme différents. Le processus enfant exécute le programme entre accolades après if (pid = = 0), c'est-à-dire l'instruction execlp ; tandis que le processus parent exécute le programme entre accolades après else.

Conseils : Les processus parent et enfant s'exécutent simultanément et la séquence d'exécution est arbitraire. Mais comme la première instruction exécutée par le processus parent est wait(null), cela signifie que le processus parent se bloquera jusqu'à ce qu'un processus enfant du processus soit suspendu ou terminé.

4. Synchronisation des processus

1. Deux contraintes

En raison de la nature asynchrone du processus, les résultats ne sont pas reproductibles. Pour éviter cette structure, il existe deux restrictions entre les processus asynchrones :

  • Relation de partage de ressources/restriction mutuelle indirecte : partage/concurrence pour certaines ressources entre elles, face à trois problèmes de contrôle :

1. Exclusion mutuelle : signifie que plusieurs processus ne peuvent pas utiliser la même ressource en même temps ;       

2. Deadlock : fait référence à plusieurs processus qui ne se cèdent pas les uns aux autres et qui ne peuvent pas obtenir suffisamment de ressources ;       

3. Faim : signifie qu'un processus n'a pas pu obtenir de ressources (d'autres processus peuvent en consommer à leur tour)

  • Relation de coopération mutuelle/restriction mutuelle directe : certaines étapes simultanées ont une relation de séquence temporelle en même temps (par exemple : la saisie, le calcul et l'impression de trois segments de programme sont exécutés simultanément en tant que trois processus), également appelée relation de synchronisation

2. Ressources critiques - problème "producteur-consommateur"

Définition : les ressources qui n'autorisent l'utilisation que d'un seul processus à la fois sont appelées ressources critiques , également appelées ressources exclusives (par exemple : imprimantes matérielles, lecteurs de bande, etc.)

Voici un problème "producteur-consommateur" pour illustrer ce processus :

------------ Problème "producteur-consommateur" ------------

Il existe un groupe de processus de production qui produisent des produits et fournissent ces produits aux processus de consommation pour la consommation. Afin de permettre au processus producteur et au processus consommateur de s'exécuter simultanément, un tampon de pool de tampons avec n tampons est défini entre les deux , et le processus producteur place le produit qu'il produit dans un tampon ; le processus consommateur Produit peut être extrait d'un tampon pour la consommation.

Bien que tous les processus producteurs et processus consommateurs s'exécutent de manière asynchrone, ils doivent être synchronisés, c'est-à-dire que le processus consommateur n'est pas autorisé à récupérer les produits d'un tampon vide ; Libérer le produit dans un tampon plein de produits et qui n'a pas encore été supprimé .

(Voir livre P53-P54) Conclusion : l'accès aux ressources critiques doit être mutuellement exclusif ! ! !

3. Section critique

En résumé, les exemples d'accès mutuellement exclusifs aux ressources critiques sont les suivants :

A: begin
         Input data 1 form I/O 1 ;
         Computer……;
         Print results 1 by printer ;  A临界区
     end
  B: begin
         Input data 1 form I/O 2 ;
         Computer……;
         Print results 2 by printer ;  B临界区
     end

Analyse : A et B ont besoin d'imprimantes, et l'ordre de A et B ne peut pas être directement restreint (la simultanéité ne peut pas être garantie) , et les restrictions doivent être aussi peu nombreuses que possible

Solution : décomposer le code de chaque processus, séparer le code qui accède aux ressources critiques (appelée section critique) des autres sections de code, et empêcher uniquement les différents processus d'entrer dans leur propre section critique , c'est-à-dire que chaque processus s'exclut mutuellement. propre zone critique. Dans les deux programmes de A et B mentionnés ci-dessus, nous appelons respectivement les programmes en deux étapes imprimer le résultat 1 par l'imprimante et imprimer le résultat 2 par l'imprimante de A et B en utilisant l'imprimante comme zone critique A et zone critique B de l'imprimante utilisé par les processus A et B , et les processus A et B doivent entrer dans leurs sections critiques respectives A et B mutuellement exclusives.

Section critique : code qui accède aux ressources critiques dans chaque processus

Un processus cyclique d'accès aux ressources critiques est le suivant :
While(TRUE)

{

  • Zone d'entrée : vérifiez la ressource critique pré-visitée, si elle n'est pas accessible, entrez-la et définissez-la comme l'indicateur auquel on accède.
  • Section critique : opérer sur des ressources critiques.
  • Zone de sortie : changez le drapeau en cours d'accès en non-accès.
  • Zone restante : codes dans le processus autres que les trois zones ci-dessus

}

Un exemple est le suivant :

begin   remainder section 1;     剩余区1
                          进入区
                         critical  section ;       临界区
     退出区
     remainder  section 2 ;   剩余区2
        end

4. Mécanisme de synchronisation du programme

Synchronisation de processus : le nom coordonné de plusieurs processus liés dans l'ordre d'exécution

Mécanisme de synchronisation des processus : utilisé pour assurer la relation de coordination de plusieurs processus dans l'ordre d'exécution

Il existe quatre directives de mécanisme de synchronisation :

(1) Idle let-in : Lorsqu'aucun processus n'entre dans la section critique, la ressource critique correspondante est dans un état inactif, permettant ainsi à un processus qui demande à entrer dans la section critique d'entrer immédiatement dans sa propre section critique.

(2) Attendre pendant qu'il est occupé : lorsqu'un processus existant entre dans sa propre zone critique, la ressource critique correspondante est en cours d'accès, de sorte que les autres processus essayant d'entrer dans la zone critique doivent attendre pour s'assurer que le processus accède exclusivement à la ressource critique.     

(3) Attente limitée : Pour les processus nécessitant un accès à des ressources critiques, il convient de s'assurer que le processus peut entrer dans la zone critique dans un temps limité, afin de ne pas tomber dans un état de "famine".

(4) Renoncer au droit d'attendre : Lorsque le processus ne peut pas entrer dans sa propre zone critique, le processeur doit être libéré immédiatement pour éviter que le processus ne tombe dans une attente occupée.

Supplément : La méthode logicielle peut résoudre le problème de l'exclusion mutuelle des processus entrant dans la zone critique, mais elle est difficile et présente de grandes limites. Généralement, des mécanismes de synchronisation matérielle sont utilisés, tels que la désactivation des interruptions, les instructions "Test-and-Set" pour réaliser l'exclusion mutuelle, et à l'aide des instructions d'échange, mettre en œuvre le programme d'exclusion mutuelle .

5. Mécanisme de sémaphore

Le mécanisme de sémaphore est un outil de synchronisation de processus proposé par Dijkstra.

5.1 Sémaphore entier

Un sémaphore était initialement défini comme un entier S représentant le nombre de ressources .

À l'exception de l'initialisation, il n'est accessible que par deux opérations atomiques standard wait(S) et signal(S) . Ces deux opérations ont été appelées respectivement opérations P et V. Les opérations d'attente et de signal peuvent être décrites comme suit :

wait(S): while S≤0 do no-op
                                S∶=S-1;
        signal(S):         S    ∶=S+1;

Astuces : L'opération atomique signifie ici que lorsqu'un processus modifie un sémaphore, les autres processus ne peuvent pas le modifier (l'opération atomique ne peut pas être interrompue)

5.2 Sémaphores enregistrés

L'opération d'attente dans le mécanisme de sémaphore entier, tant que le sémaphore S≤0, continuera à tester, et il y a une attente occupée. Le mécanisme de sémaphore d'enregistrement a été optimisé. Cependant, après avoir adopté la stratégie de "renoncer au droit d'attendre", il y aura une situation où plusieurs processus attendent d'accéder à la même ressource critique. Pour cette raison, dans le mécanisme de sémaphore, en plus d'une valeur de variable entière utilisée pour représenter le nombre de ressources, une liste de pointeurs de liste de processus (L) doit être ajoutée pour relier tous les processus en attente mentionnés ci-dessus. Les deux éléments de données ci-dessus qu'il contient peuvent être décrits comme :

type semaphore=record
         value:integer;
         L:list of process; //记录阻塞控制进程
         end
相应地,wait(S)和signal(S)操作可描述为:
procedure wait(S)
     var S: semaphore;
     begin
       S.value∶   =S.value-1;
       if S.value<0 then block(S,L) //该类资源已分配完成,自我阻塞(勿忙等),让出CPU
     end
  procedure signal(S)
     var S: semaphore;
     begin
      S.value∶   =S.value+1;
      if S.value≤0 then wakeup(S,L); //如果增加了资源,仍有等待该资源的进程被阻塞,则唤醒它
     end

Astuces : Si S->value = 1 (initialisation), le sémaphore devient alors un sémaphore d'exclusion mutuelle, qui est utilisé pour l'exclusion mutuelle des processus.

5.3 Types de sémaphores

Les sémaphores sont divisés en deux catégories selon la relation du processus de contact :  

(1) Sémaphore public (sémaphore mutuellement exclusif) : il est défini pour un groupe de processus concurrents qui ont besoin de s'exclure mutuellement et de partager des ressources critiques. Il représente une ressource critique partagée permanente , et chaque processus peut lui imposer P, V. opération , c'est-à-dire que la ressource critique peut être demandée et libérée, et sa valeur initiale est définie sur 1.

(2) Sémaphore dédié (sémaphore synchrone) : il est défini pour un groupe de processus concurrents qui doivent se synchroniser et coopérer pour accomplir des tâches. Il représente une ressource dédiée consommable. Seul le processus propriétaire de la ressource peut lui appliquer des opérations P ( c'est-à-dire demander des ressources), et l'opération V lui est imposée par son processus coopératif (c'est-à-dire libérer des ressources) .

Valeur du sémaphore S (S.value) signifiant :

  • >0 ; Indique le nombre de ressources disponibles
  • =0 ; Indique que la ressource a été occupée et qu'il n'y a pas d'autre processus en attente.        
  • <0 (=-n); Indique que la ressource a été occupée et que n processus sont bloqués en raison de l'attente de ressources.

Voici un exemple d'utilisation de sémaphores pour protéger les données partagées :

5.4 Sémaphore de type ET

Le sémaphore précédent permet principalement à plusieurs processus de partager une ressource critique, mais la situation réelle est généralement plusieurs à plusieurs. Un exemple est le suivant :

Les deux processus doivent contenir deux opérations sur Dmutex et Emutex (les deux processus A et B doivent accéder aux données partagées D et E), à savoir :

Si les processus A et B effectuent alternativement les opérations d'attente dans l'ordre suivant :

Ⅰ、processus A : attendre(Dmutex); 于是Dmutex=0

Ⅱ、processus B : attendre(Emutex) ; donc Emutex=0

Ⅲ, process A : wait(Emutex) ; donc Emutex=-1 A bloque

Ⅳ、process B : wait(Dmutex) ; donc Dmutex=-1 blocs B

Jusqu'à présent, A et B sont entrés dans une impasse (il n'y a pas de force externe pour se débarrasser de l'impasse, et aucun ne peut obtenir les ressources souhaitées). Plus il y a de ressources à partager entre les programmes, plus il est facile pour l'impasse arriver.  

Par conséquent, le sémaphore de type AND est introduit et l'idée de base de son mécanisme de synchronisation est la suivante : toutes les ressources nécessaires au processus pendant tout le processus en cours d'exécution sont allouées au processus en même temps et libérées ensemble une fois le processus terminé. épuisé . C'est-à-dire que pour l'allocation de plusieurs ressources critiques, on adopte une opération atomique : soit elles sont toutes allouées au processus, soit aucune d'entre elles n'est allouée . De cette manière, l'apparition de la situation de blocage mentionnée ci-dessus peut être évitée. Pour cette raison, dans l'opération d'attente, une condition "ET" est ajoutée, elle est donc appelée synchronisation ET, ou une opération d'attente simultanée, c'est-à-dire que Swait (attente simultanée) est défini comme suit :

Swait(S1, S2, …, Sn)
    if Si≥1 and … and Sn≥1 then
        for i∶ =1 to n do
        Si∶=Si-1;
        endfor
    else
     place the process in the waiting queue associated with the first Si found   with Si<1, and set the program count of this process to the beginning of Swait operation
    endif
Ssignal(S1, S2, …, Sn)
      for i∶   =1 to n do
      Si=Si+1;
      Remove all the process waiting in the queue associated with Si into the ready queue.
  endfor; 

5.5 Collecte de quantité de signal

Dans les opérations de sémaphore précédentes, une seule unité de ressources critiques peut être demandée/libérée à la fois, ce qui est relativement inefficace, augmente la probabilité de blocage et nécessite de juger du nombre de ressources à chaque fois pour la sécurité du système.

Par conséquent, le jeu de sémaphores est introduit et développé sur la base de ET Pour toutes les ressources demandées et les différentes demandes de chaque ressource, il est complètement appliqué ou libéré dans une primitive P et V .

Paradigme : Swait (S, t, d) S est le sémaphore (le montant total actuel) t est l'allocation minimale à un moment donné et d est la demande à un moment donné

Ssignal (S, d) signifie la même chose que ci-dessus

Processus : jugement en boucle -> allocation

Swait(S1, t1, d1, …, Sn, tn, dn)
    if S1≥t1 and … and Sn≥tn then //ti为该资源分配下限值
      for i∶=1 to n do
        Si∶=Si-di //di为对该资源的需求值
    endfor
   else
   Place the executing process in the waiting queue of the first Si with Si<ti and set its program counter to the beginning of the Swait Operation. 
   endif

   Ssignal(S1, d1, …, Sn, dn)
   for i∶=1 to n do
     Si ∶=Si+di;
Remove all the process waiting in the queue associated with Si into the ready queue
   endfor; 

Plusieurs cas particuliers du "jeu de sémaphores" général :        

(1) Swait(S, d, d). À ce moment, il n'y a qu'un seul sémaphore S dans l'ensemble de sémaphores, mais il est autorisé à demander à chaque fois des ressources d. Lorsque le nombre de ressources existantes est inférieur à d, il ne sera pas alloué.        

(2) Attendre(S, 1, 1). A ce moment, l'ensemble de sémaphores a dégénéré en un sémaphore d'enregistrement général (lorsque S>1) ou un sémaphore d'exclusion mutuelle (lorsque S=1).        

(3) Swait(S, 1, 0). Il s'agit d'une opération de sémaphore très spéciale et utile. Lorsque S≥1, plusieurs processus sont autorisés à entrer dans une zone spécifique ; lorsque S devient 0, tout processus sera empêché d'entrer dans une zone spécifique. En d'autres termes, il équivaut à un interrupteur commandable.

6. Application du sémaphore

6.1 Utiliser des sémaphores pour réaliser un processus d'exclusion mutuelle

Core : Définissez un mutex de sémaphore d'exclusion mutuelle, initialisé à 1, et utilisez wait (mutex) et signal (mutex) pour accéder à .

Voici un exemple d'utilisation d'un sémaphore pour implémenter l'exclusion mutuelle entre deux processus :

var mutex:=semaphore:=1 ;
begin
parbegin
A:begin                    B:begin
 Input data 1 from I/0 1 ; Input data 2 from I/O 2 ;
 Compute……;              Compute……;
 P(mutex) ;申请资源        P(mutex) ;申请资源
 Print results1 by printer; Print results2 by printer; 
(临界区A--使用资源)   (临界区B--使用资源)
 V(mutex) ;释放资源        V(mutex) ;释放资源
 end                                      end
parend
end

Conseils : attente (mutex) et signal (mutex) doivent apparaître par paires. 

6.2 Utiliser des sémaphores pour réaliser la relation de prédécesseur

Prenons comme exemple le diagramme précurseur suivant :

Le code implémenté avec sémaphore est le suivant :

Var a,b,c,d,e,f,g; semaphore∶=0,0,0,0,0,0,0;
      begin
          parbegin
     	begin S1; signal(a); signal(b); end;
     	begin wait(a); S2; signal(c); signal(d); end;
     	begin wait(b); S3; signal(e); end;
     	begin wait(c); S4; signal(f); end;
     	begin wait(d); S5; signal(g); end;
     	begin wait(e); wait(f); wait(g); S6; end;
        parend
   end 

6.3 Utilisation du mécanisme de sémaphore pour réaliser la synchronisation des processus

Un exemple (processus de calcul C->buffer buffer->processus d'impression P) est le suivant :

Les algorithmes de base des processus C et P sont les suivants :

C:begin                  P:  begin  
   repeat                     repeat
    Compute next number ;     remove from Buffer ;
    add to Buffer ;           print last number ;
    until false               until false
   end                        end

Conseils : Afin d'assurer une exécution simultanée normale, l'ordre doit être suivi (C entre P pour l'obtenir, P prend C puis entre nouveau) 

Pour réaliser la synchronisation, un sémaphore de synchronisation est utilisé .

(1) Afin de respecter la première règle de synchronisation : seulement après que le processus C a envoyé des données dans le tampon, le processus P peut extraire les données du tampon pour les imprimer. Définissez un sémaphore synchrone full , qui représente une ressource dédiée consommable pleine de données dans le tampon. Cette ressource n'appartient qu'au processus (processus P) qui exécute l'action (Supprimer du tampon) ultérieurement, et le processus P peut s'appliquer pour cette ressource avant l'action. , appliquez-lui l'opération P, si la condition est satisfaite, le processus P peut obtenir le numéro de Buffer et sa valeur initiale est 0 . Le processus d'action précédent (le processus coopératif C du processus P) applique l'opération V au sémaphore complet une fois l'action (Ajouter au tampon) terminée, c'est-à-dire que lorsque le processus C stocke les données dans le tampon, la ressource peut être libéré pour que le processus P puisse être réutilisé. Un programme de type PASCAL qui implémente la première règle de synchronisation de deux processus C et P :

var: full:semaphore:=0 ;
 begin
  parbegin
   C: begin
       repeat
        Compute next number ;
        
        Add to buffer ;
        V(full) ; //告知P有新数据
       until false 
      end
  P: begin
      repeat
       P(full) ; //有新数据才拿
       remove from Buffer ;
       
   Print last number ;
     until false
    end
 parend
end

 (2) Afin de respecter la deuxième règle de synchronisation : seulement après que le processus P a pris les données du tampon, le processus C peut stocker les données nouvellement calculées dans le tampon. Définissez un autre sémaphore synchrone vide , qui représente une ressource dédiée consommable qui est un tampon vide. Cette ressource n'appartient qu'au processus (processus C) à l'origine de l'action (Ajouter au tampon). Le processus C peut demander cette ressource avant l'action. Appliquez-lui l'opération P, si la condition est satisfaite, le processus C peut demander la ressource et sa valeur initiale est 1 . Le processus de l'action précédente (Supprimer du tampon) (le processus coopératif P du processus C) applique l'opération V au sémaphore vide une fois l'action terminée, c'est-à-dire que lorsque le processus P prend les données du tampon, il peut libérer la ressource pour la réutilisation du processus C. 

Le code pour considérer deux relations de synchronisation est le suivant (regardez principalement les quatre phrases du commentaire, à savoir le mécanisme de sémaphore):

var: empty,full:semaphore:=1,0 ;
 begin
  parbegin
   C: begin
       repeat
        Compute next number ;
        P(empty) ;// 若数据已被读取过,将新数据放入buffer
        Add to buffer ;
        V(full) ;// 告知P有新数据
       until false 
      end
  P: begin
      repeat
       P(full) ;// 若有新数据,则拿
       remove from Buffer ;
       V(empty) ;// 告知C数据已读取
   Print last number ;
     until false
    end
 parend
end

La signification physique de la synchronisation : l' opération V signifie envoyer un message ; l'opération P signifie tester si le message est arrivé .

Les exercices sont les suivants :

Question : Il existe trois processus simultanés P, Q et R, et une paire de tampons BufI et BufO pour stocker les données. Le processus P entre les données dans BufI et le processus R sort les données dans BufO. Q ground transforme les données dans BufI et les envoie à BufO Sous les hypothèses ci-dessus, les trois processus peuvent atteindre un parallélisme maximal. Essayez de remplir le sémaphore, la valeur initiale du sémaphore et les opérations P et V dans les positions de la ligne pointillée du programme de type PASCAL suivant pour réaliser l'exécution simultanée correcte des trois processus.  

Semblable au code de l'exemple ci-dessus, sauf que Q peut faire à la fois le dernier et le premier, et le sémaphore a également deux ensembles de plein et vide.

7. Problème de synchronisation de processus classique

Quelques exemples typiques d'exécution simultanée de processus sont résumés, qui sont souvent utilisés pour tester la faisabilité de nouveaux mécanismes de synchronisation.

7.1 Problème producteur-consommateur

Le problème producteur-consommateur est le problème de synchronisation le plus connu, qui décrit un groupe de producteurs (P1...Pm) fournissant des messages à un groupe de consommateurs (C1...Cq). Ils partagent un pool de mémoire tampon limité, où les producteurs placent des messages et où les consommateurs reçoivent des messages de leur part, comme illustré dans la figure ci-dessous. Le problème producteur-consommateur est une abstraction de nombreux processus coopérants.

Conseils : Le pool tampon doit être mutuellement exclusif entre producteurs, entre producteurs et consommateurs et entre consommateurs . Vous devez donc définir le sémaphore d'exclusion mutuelle mutex , qui représente la ressource du pool de mémoire tampon, et sa valeur est 1

Semblable aux exemples 6 et 3 (sauf que le tampon est ici une ressource critique), l'ordre dans le problème de synchronisation est très important. Ce n'est que lorsque P est transmis à C qu'il peut être connecté, et C doit être connecté à P pour transmettre un nouveau, donc un sémaphore plein et un signal vide sont également requis.

L'exemple de code (utilisant le sémaphore d'enregistrement) est le suivant :
 

var mutex,empty,full:semaphore:=1,n,o ;
Buffer : array [0……n-1] of message ;
in, out : o……n-1:=0,0 ;
begin
 parbegin
     Pi: begin (i=1...m)
         repeat
          Produce a new message m ;
          P (empty) ;申请empty资源
          P (mutex) ;申请共享资源
          Buffer[in]=m ;
          in :=(in+1) mod n ;
          V (mutex) ;释放共享资源
          V (full) ; 释放full资源 
         until false
        end
    Cj: begin (j=1...q)
         repeat
           P (full) ; 申请full资源
           P (mutex) ;申请共享资源
           m := buffer[out] ;
           out : = (out+1) mod n ;
           V (mutex) ;释放共享资源
           V (empty) ;释放empty资源
           Consume message m ;
         until false
       end
   parend
end

Sémaphore de ressource - plein vide (exécuté en premier), sémaphore d'exclusion mutuelle - mutex (exécuté plus tard)

Conseils : Le cache ici est un cache circulaire , donc la condition de changement est change :=(base+1) mod n ; le pool de tampons est plein et change_in ((in+1) mod n ) = out , in == out signifie la piscine est vide .

Conseils : wait et signal doivent apparaître par paires, et les paires de sémaphores de ressources se trouvent dans des programmes différents.

L'exemple de code (utilisant le sémaphore AND) est le suivant : 

Var mutex, empty, full:semaphore∶   =1, n, 0;
    buffer:array[0, …, n-1] of item;
    in out:integer∶   =0, 0;
   begin
    parbegin
      producer:begin
            repeat
             …
            produce an item in nextp;
             …
            Swait(empty, mutex);
            buffer(in)∶   =nextp;
            in∶   =(in+1)mod n;
            Ssignal(mutex, full);
           until false;
         end
consumer:begi
            repeat
             Swait(full, mutex);
             nextc∶   =buffer(out);
             out∶   =(out+1) mod n;
             Ssignal(mutex, empty);
             consumer the item in nextc;
            until false;
         end
      parend
    end 

Utilisez Swait (x, y) et Ssignal (x, y) pour remplacer la double attente et le double signal d'origine. 

7.2 Problèmes de gestion de la salle de lecture (variantes production et élimination)

  • Il y a un certain nombre de places dans la salle de lecture, où un certain nombre d'étudiants peuvent s'asseoir pour l'auto-apprentissage ; il y a un formulaire d'inscription unique, qui enregistre le nombre de places vacantes
  • Lorsqu'un étudiant entre dans la salle, vérifiez le formulaire d'inscription ; si le nombre de places vacantes est > 0, alors le nombre de places sera réduit d'une, et entrez dans la salle de lecture pour vous asseoir et étudier ; sinon, attendez à la porte de la salle de lecture
  • A la sortie de la salle de lecture, augmenter de 1 le nombre de places libres dans le formulaire d'inscription

La seule différence avec "producteur-consommateur" est que le siège n'a besoin que d'un siège de sémaphore, et la déclaration est bonne (pas besoin de plein et de vide).

Un échantillon est le suivant (50 places):

var mutex, seat: semaphore := 1, 50                                //定义变量
procedure roomin;         //进门进程
begin
    wait(seat);    
    wait(mutex);
    登记,同学进入阅览室……;
    signal(mutex);
        :
end;
procedure roomout;    //出门进程
begin
    wait(mutex);
    撤消登记,同学走出阅览室….;
    signal(mutex);
    signal(seat);
        :
end;

7.3 Le problème des philosophes de la restauration

Cinq philosophes partagent une table ronde avec cinq bols et cinq baguettes Ils pensent et mangent alternativement. Lorsque vous avez faim, essayez de prendre les deux baguettes les plus proches à gauche et à droite et ne mangez que lorsque vous en avez 2. Après avoir mangé, posez les baguettes et continuez à réfléchir.

Utilisez d'abord le sémaphore d'enregistrement pour résoudre le problème :

Les baguettes sont des ressources critiques et un sémaphore (tous deux initialisés à 1) peut être utilisé pour représenter une baguette .

//第i位哲学家的活动
 repeat
   	 wait(chopstick[i]); // 拿左边的筷子
    	wait(chopstick[(i+1) mod 5]); //拿右边的筷子
      		…
   	 eat;
                             …
   	 signal(chopstick[i]);
   	 signal(chopstick[(i+1) mod 5]);
     	              …
   	 think;
  until false; 

Le code ci-dessus ne permettra pas à deux philosophes de manger en même temps, mais cela peut provoquer une impasse (les cinq personnes reçoivent la baguette gauche). Il existe plusieurs solutions :

 (1) Au plus quatre philosophes sont autorisés à prendre les baguettes de gauche en même temps. Enfin, au moins un philosophe peut être assuré de manger, et il peut lâcher les deux baguettes qu'il a utilisées lorsqu'il a fini de les utiliser, de sorte que plus de philosophes peuvent manger.        

(2) Ce n'est que lorsque les baguettes gauche et droite du philosophe sont disponibles qu'il est autorisé à prendre des baguettes pour manger.         

(3) Il est stipulé que les philosophes impairs prennent d'abord la baguette sur sa gauche, puis vont à la baguette sur la droite; tandis que les philosophes pairs font le contraire. Selon cette règle, les philosophes n° 1 et n° 2 se disputeront la baguette n° 1 ; les philosophes n° 3 et n° 4 se disputeront la baguette n° 3. C'est-à-dire que les cinq philosophes se disputent d'abord les baguettes impaires, puis se disputent les baguettes paires après les avoir obtenues.En fin de compte, il y aura toujours un philosophe qui pourra obtenir deux baguettes et manger. 

Ensuite, venez au sémaphore ET pour résoudre le problème de restauration du philosophe (la solution la plus concise), qui est essentiellement la deuxième solution :

Var chopsiick array [0, …, 4] of semaphore∶   =(1,1,1,1,1);
    processi
        repeat
        think;
        Sswait(chopstick[(i+1) mod 5], chopstick [i]);
        eat;
        Ssignat(chopstick [(i+1) mod 5], chopstick [i]);
      until false; 

7.4 Le problème lecteur-écrivain

Un fichier ou un enregistrement de données peut être partagé par plusieurs processus, on appelle le processus qui ne demande qu'à lire le fichier "Reader", et les autres processus sont appelés "Writer". Le problème du lecteur-écrivain garantit essentiellement qu'un processus Writer doit être mutuellement exclusif avec d'autres processus (les opérations de lecture ne changeront pas les données, mais les opérations d'écriture le feront).

Tout d'abord, utilisez le sémaphore d'enregistrement pour résoudre le problème. Le noyau est le suivant :

Readcount - le nombre de processus qui lisent Wmutex - le sémaphore mutex du processus Writer

rmutex - Sémaphore d'exclusion mutuelle du processus de lecture (puisque Readcount peut être lu par plusieurs processus)

Analyse détaillée : Un sémaphore d'exclusion mutuelle Wmutex est configuré pour réaliser une exclusion mutuelle entre les processus Reader et Writer lors de la lecture ou de l'écriture. De plus, définissez une variable entière Readcount pour indiquer le nombre de processus en cours de lecture. Parce que tant qu'il y a un processus Reader en lecture, le processus Writer n'est pas autorisé à écrire. Par conséquent, uniquement lorsque Readcount = 0, indiquant qu'il n'y a pas de lecture du processus Reader, le processus Reader doit exécuter l'opération Wait (Wmutex). Si l'opération wait(Wmutex) réussit, le processus Reader peut lire et, par conséquent, effectuer l'opération Readcount+1. De même, uniquement lorsque la valeur de Readcount est 0 après que l'opération Readcount moins 1 a été effectuée par le processus Reader, l'opération de signal (Wmutex) doit être exécutée pour permettre au processus Writer d'écrire. Et comme Readcount est une ressource critique à laquelle plusieurs processus Reader peuvent accéder, un sémaphore mutex rmutex doit être défini pour celle-ci.

var rmutex, wmutex: semaphore := 1, 1 ; 定义变量
     readcount: integer: =0;
procedure reader;     读者进程
begin
    repeat
        wait(rmutex);
        if readcount = 0 then wait(wmutex); // then即满足条件执行,这里即有读进程不让写所以wait让其-1
        readcount := readcount + 1;
        signal(rmutex);
        执行读操作
        wait(rmutex);
        readcount := readcount - 1;
        if readcount = 0 then signal(wmutex);
        signal(rmutex);
    until false;
end;
procedure writer;                    写者进程
begin
    repeat
        wait(wmutex);
        执行写操作;
        signal(wmutex); 
    until false;
end;

Une limitation est ajoutée ici, seuls les lecteurs RN sont autorisés à lire en même temps , donc le mécanisme d'ensemble de sémaphores est introduit pour le résoudre.

Noyau : lorsque le lecteur RN+1 entre, il est bloqué à cause de Swait(L, 1, 1) ;

var L, mx: semaphore := RN, 1 ; 定义变量
procedure reader;            读者进程
begin
    repeat
        Swait(L, 1, 1);
        Swait(mx, 1, 0);
        执行读操作
        Ssignal(L, 1);
    until false;
end;
procedure writer;                    写者进程
begin
    repeat
        Swait(mx, 1, 1; L, RN, 0);
        执行写操作;
        Ssignal(mx, 1); 
    until false;
end;

Analyse : Swait(mx, 1, 0); est un commutateur qui détermine si mx est égal à 1 (avec ou sans écrivain) et détermine s'il faut lire ou non. Swait(mx, 1, 1; L, RN, 0); est un jugement double , ni l'écrivain n'écrit (mx>=1) ni le lecteur ne lit (L>= RN), de sorte que le processus d'écriture entre dans le section critique.

À faire : les écrivains d'abord

7.5 Traverser le problème du pont à une planche (variantes de lecture et d'écriture)

Il y a un pont à une seule planche nord-sud.S'il y a une personne sur le pont, la personne dans la même direction peut monter sur le pont et passer, et la personne dans la direction opposée ne peut qu'attendre.

Le problème du pont à une seule planche est en fait un problème de deux types de processus (lecteur) accédant à un objet partagé en même temps . Le même type de processus (lecteur) peut fonctionner (lire) en même temps, mais différents types de ( lecteur) les processus ne peuvent pas fonctionner (lire) simultanément. Par exemple :

Problèmes d'expédition du barrage des Trois Gorges

Problèmes de navigation sur le canal de Panama

Un exemple pratique est donné par code :

//因为sCount和nCount都被多程序共享,故访问/改变前要使用smutex和nmutex
var mutex, smutex, nmutex: semaphore := 1, 1, 1 ; 定义变量(桥信息量,南桥信息量,北桥信息量)
     sCount, nCount: integer: =0;
procedure SouthPassenger;                 //南桥头行人进程
begin
    wait(smutex);
    if sCount = 0 then wait(mutex);    //得到过桥权
    sCount := sCount + 1;
    signal(smutex);
    向北,过桥……
    wait(smutex);
    sCount := sCount - 1;
    if sCount = 0 then signal(mutex);   //释放过桥权
    signal(smutex);
end;
procedure NorthPassenger;              //北桥头行人进程
begin
    wait(nmutex);
    if nCount = 0 then wait(mutex);    //得到过桥权
    nCount := nCount + 1;
    signal(nmutex);
    向南,过桥……
    wait(nmutex);
    nCount := nCount - 1;
    if nCount = 0 then signal(mutex);   //释放过桥权
    signal(nmutex);
end;

8. Mécanisme de surveillance

Bien que le mécanisme de sémaphore soit pratique, la plupart des opérations de synchronisation sont dispersées dans chaque processus et peuvent provoquer un blocage en raison d'un fonctionnement incorrect. Un autre outil de surveillance de synchronisation de processus est donc introduit .

8.1 Définition

Un moniteur définit une structure de données et un ensemble d'opérations (sur la structure de données) qui peuvent être effectuées par des processus concurrents , qui peuvent synchroniser les processus et modifier les données dans le moniteur

Un moniteur est en fait une collection de sous-programmes spéciaux (fonctions, procédures) qui peuvent réaliser la synchronisation des processus

Un moniteur se compose des éléments suivants :

  • Nom : L'ID du moniteur
  • Description de la variable partagée : description de la variable locale au moniteur (y compris les variables de synchronisation spéciales ou les variables de condition)
  • Un ensemble de procédures : le segment de programme qui opère sur la structure de données (équivalent au segment de code section critique)
  • Initialisation : Définir les valeurs initiales pour les données locales au moniteur

La structure grammaticale est la suivante :

Type 管程名称 = monitor
    共享变量说明语句
    procedure entry P1(…)
        begin    …    end;
    procedure entry P1(…)
        begin    …    end;
           :
    begin
        初始化语句
    end;

Le cœur du moniteur pour réaliser la synchronisation des processus est le suivant :

Accès mutuellement exclusif pour les processus :

  • L'accès des processus aux ressources critiques doit passer par le moniteur
  • Le moniteur n'autorise qu'un seul processus à entrer à la fois 

Synchronisation des processus :

  • Définir une variable de condition (équivalente à un sémaphore mutex) var x : condition
  • Lorsque la ressource critique est occupée, exécutez x.wait et suspendez le processus dans la file d'attente bloquante de la variable de condition x
  • Lorsque la ressource critique est libre, exécutez x.signal et réveillez le premier processus de la file d'attente bloquante de la variable de condition x

8.2 Exemple (problème producteur-consommateur)

1. Processus :

  • put(item) process Le producteur place le produit dans le buffer
  • processus get(item) Le consommateur obtient un produit du tampon

2. Variables :

  • Integer in, out : la valeur initiale est 0, in indique le numéro de série du premier bloc de tampon vide et out indique le numéro de série du premier bloc de tampon plein
  • Tampon[0...n-1] : tampon
  • Nombre d'entiers : le nombre de blocs de tampon pleins
  • Variable de condition notfull, notempty : indique que le buffer est plein ou vide (propre au moniteur)

3. Description des tubes

Type PC = monitor
    var in, out, count: integer;
         buffer: array[0, …, n-1] of item;
         notfull, notempty: condition;
    procedure entry put(var nextp: item)
        begin
            if count >= n then notfull.wait //缓冲区已满 生产者需等待
            buffer(in) := nextp;
            in := (in + 1) mod n;
            count := count + 1;
            if notempty.queue then notempty.signal //队列不为空选择一个唤醒
        end;
    procedure entry get(var nextc: item)
        begin
            if count <= 0 then notempty.wait //缓冲区为空 消费者需等待
            nextc := buffer(in);
            out := (out + 1) mod n;
            count := count - 1;
            if notfull.queue then notfull.signal //队列不为空选择一个唤醒
        end;
    
    begin
        in :=0; out := 0; count := 0; 
    end;

4. Descriptif du processus :

procedure producer;      生产者进程
begin
    repeat
        生产一个产品nextp;
        PC.put(nextp);
    until false;
end;
procedure consumer;    消费者进程
begin
    repeat
        PC.get(nextc);
        消费一个产品nextc;
    until false;
end;

Avantages des tubes :

  • Très simple lors d'appels depuis des processus utilisant des ressources critiques
  • La structure du processus est claire
  • facile à dépanner

Cinq, processus de communication

La communication de processus fait référence à l'échange d'informations entre processus , tandis que l'exclusion mutuelle et la synchronisation appartiennent à la communication de bas niveau, qui est inefficace et opaque pour les utilisateurs , d'autres outils/méthodes de communication avancés sont donc nécessaires.

1. Type de communication de processus

1.1 Système de mémoire partagée

Les systèmes de mémoire partagée sont généralement basés sur des structures de données partagées et des zones de stockage partagées .

Ⅰ. Communication basée sur une structure de données partagée

L'utilisation de structures de données partagées, telles que les tampons producteur-consommateur, est inefficace et convient à de petites quantités de transfert de données.

Ⅱ. Communication basée sur une zone de stockage partagée

Le mécanisme avec la plus grande vitesse de communication dans le système UNIX Afin de transmettre une grande quantité de données, une zone de stockage est allouée dans la zone de stockage pour le partage par plusieurs processus.

Une fois que les processus A et B ont établi une zone de stockage partagée et obtenu son descripteur, ils doivent utiliser l'appel système shmat pour attacher la zone de stockage partagée à l'espace d'adressage virtuel de leurs processus respectifs , comme illustré dans la figure ci-dessous. Après cela, la zone de stockage partagée fait partie de l'espace d'adressage virtuel du processus, et le processus peut y accéder de la même manière que les autres espaces d'adressage virtuels.

Lorsque les processus A et B utilisent la zone de stockage partagée pour communiquer, ils doivent mettre en place un mécanisme de synchronisation des processus pour assurer une communication correcte. Lorsque les processus A et B utilisent la zone de stockage partagée pour communiquer, ils peuvent également utiliser l'appel système shmctl pour lire les informations d'état (telles que la longueur, le nombre de processus actuellement connectés, etc.) de la zone de stockage partagée, et peuvent également définir et modifiez les propriétés de la zone de stockage partagé (telles que les autorisations pour le stockage partagé, etc.). Enfin, l'appel système shmctl peut toujours être utilisé pour déconnecter le processus de la zone de stockage partagée. Lorsque tous les processus se sont déconnectés de la mémoire partagée, la mémoire partagée peut être non partagée.

1.2 Système de messagerie

Le mécanisme de transmission de messages est le mécanisme de communication interprocessus le plus largement utilisé. L'échange de données entre processus se fait en unités de messages formatés . Les programmeurs utilisent directement un ensemble de commandes de communication (primitives) fournies par le système pour communiquer . Le système d'exploitation masque les détails de mise en œuvre de la communication, ce qui réduit considérablement la complexité de la programmation de la communication. Le procédé de communication du système de messagerie appartient au procédé de communication avancé. Divisé en deux types de communication directe et de communication indirecte :

I. Communication directe

Envoyer directement à l'aide des primitives du système d'exploitation

Ⅱ. Communication indirecte

L'envoi et la réception se font par l'intermédiaire d'une entité intermédiaire partagée (boîte aux lettres).

1.3 Communication par canalisation (tuyau)

"Pipeline" fait référence à un fichier partagé utilisé pour connecter le processus de lecture et le processus d'écriture pour réaliser la communication entre eux. Le processus d'envoi qui fournit une entrée au pipeline envoie une grande quantité de données dans le pipeline sous la forme d'un flux de caractères ; le processus de réception qui accepte la sortie du pipeline reçoit (lit) les données du pipeline.

#include <stdio.h>
main()
{
  int x,fd[2];
  char buf[30],s[30];
  pipe(fd);  /*创建管道*/
  while((x=fork()) == -1); /*创建子进程失败时,循环*/
  if(x == 0)
  {
     sprintf(buf,  "This is an example\n");
     write(fd[1],buf,30); /*把buf中字符写入管道*/
     exit(0);
   }
   else {
      wait(0);
      read(fd[0],s,30);  /*父进程读管道中字符*/
      printf("%s",s);
    }
  }

Afin de coordonner la communication entre les deux parties, le mécanisme de pipeline doit disposer des trois capacités de coordination suivantes :

① Exclusion mutuelle : Lorsqu'un processus effectue des opérations de lecture/écriture sur le tube, d'autres (autres) processus doivent attendre.

②Synchronisation : lorsque le processus d'écriture écrit une certaine quantité de données dans le tube, il se met en veille et attend que le processus de lecture prenne les données, puis le réveille. Lorsque le processus de lecture lit un tube vide, il doit également dormir et attendre que le processus d'écriture écrive des données dans le tube avant de le réveiller.

③Vérification de l'existence : la communication ne peut être établie que lorsqu'il est déterminé que l'autre partie existe.

1.4 Système client-serveur

Les mécanismes actuels de mise en œuvre de la communication grand public sont principalement divisés en trois catégories : les sockets, les appels de procédure à distance et les appels de méthode à distance.

2. Mise en œuvre de la communication par passage de messages

2.1 Communication directe - Messagerie directe

Cela signifie que le processus d'envoi utilise la commande d'envoi fournie par le système d'exploitation pour envoyer directement le message au processus cible. À ce stade, le processus d'envoi et le processus de réception sont tous deux tenus de fournir l'identifiant de l'autre partie de manière explicite . Généralement, le système fournit les deux commandes de communication suivantes (primitives) :

  •           Envoyer (récepteur, message) ; envoyer un message au processus de réception ;
  •           Recevoir (Expéditeur, message); Recevoir le message envoyé par l'Expéditeur ;

Il s'agit d'une méthode d'adressage symétrique , mais une fois qu'un nom de processus est modifié, cela affectera beaucoup de communication, ce qui n'est pas propice à la modularisation.

Dans certains cas, le processus de réception peut communiquer avec plus d'un processus d'envoi, il n'est donc pas possible de spécifier le processus d'envoi à l'avance. Par exemple, un processus utilisé pour fournir des services d'impression peut recevoir des messages de "demande d'impression" de n'importe quel processus. Pour une telle application, le paramètre de processus source dans la primitive de réception du processus de réception est la valeur de retour une fois la communication terminée, et la primitive de réception peut être exprimée comme :

  •          Recevoir (identifiant, message) ;  

Conseils : id peut être défini comme processus expéditeur ou nom pour la communication, qui est le mode d'adressage asymétrique .

On peut utiliser des primitives de communication directe pour résoudre le problème "producteur-consommateur"

 repeat
      …
    produce an item in nextp;
      …
    send(consumer, nextp);
   until false;
   repeat
    receive(producer, nextc);
      …
    consume the item in nextc;
  until false; 

2.2 Communication indirecte - Communication par boîte vocale

(1) Création et suppression de boîtes aux lettres. Un processus peut créer une nouvelle boîte aux lettres à l'aide de la primitive de création de boîte aux lettres. Le processus créateur doit donner le nom de la boîte aux lettres, les attributs de la boîte aux lettres (publique, privée ou partagée) ; pour les boîtes aux lettres partagées, le nom du partageur doit également être donné. Lorsqu'un processus n'a plus besoin de lire la boîte aux lettres, il peut être annulé à l'aide de la primitive d'annulation de boîte aux lettres.         

(2) Envoi et réception de messages. Lorsque les processus souhaitent utiliser des boîtes aux lettres pour communiquer, ils doivent utiliser des boîtes aux lettres partagées et utiliser les primitives de communication suivantes fournies par le système pour communiquer.

  • Envoyer (boîte aux lettres, message) ; envoyer un message à la boîte aux lettres spécifiée ;         
  • Recevoir (boîte aux lettres, message); Recevoir un message de la boîte aux lettres spécifiée ; 

Les boîtes aux lettres peuvent être créées (propriétaires) par des processus système ou utilisateur et peuvent être réparties dans les trois catégories suivantes :
Ⅰ. Boîtes aux lettres privées

Un processus utilisateur peut créer une nouvelle boîte aux lettres pour lui-même dans le cadre du processus. Le propriétaire de la boîte aux lettres a le droit de lire les messages de la boîte aux lettres et les autres utilisateurs ne peuvent envoyer que des messages composés par eux-mêmes à la boîte aux lettres. Cette boîte aux lettres privée peut être mise en œuvre à l'aide d'une boîte aux lettres avec un lien de communication à sens unique . Lorsque le processus propriétaire de la boîte aux lettres se termine, la boîte aux lettres disparaît avec lui.

Ⅱ. Boîte aux lettres publique

Il est créé par le système d'exploitation et mis à la disposition de tous les processus autorisés du système (émission et réception). De toute évidence, les boîtes aux lettres publiques doivent être mises en œuvre à l'aide de boîtes aux lettres avec des liens de communication bidirectionnels . Généralement, la boîte aux lettres publique existe pendant toute la durée de vie du système.

Ⅲ. Boîte aux lettres partagée

Il est créé par un processus, et lors de sa création ou après sa création, il est indiqué qu'il peut être partagé, et le nom du processus partagé (utilisateur) doit être indiqué en même temps. Le propriétaire et le partageur de la boîte aux lettres ont le droit de retirer les messages qui leur sont envoyés de la boîte aux lettres.

Lors de l'utilisation de la communication par boîte aux lettres, il existe les quatre relations suivantes entre le processus d'envoi et le processus de réception :       

(1) Relation univoque . A ce moment, une liaison de communication dédiée peut être établie entre le processus d'envoi et le processus de réception, de sorte que l'interaction entre les deux ne soit pas perturbée par d'autres processus.        

(2) Relation plusieurs-à-un . Permet au processus fournissant le service d'interagir avec plusieurs processus utilisateur , également appelé interaction client/serveur .    

(3) Relation un-à-plusieurs . Un processus émetteur est autorisé à interagir avec plusieurs processus récepteurs , afin que le processus émetteur puisse envoyer des messages aux récepteurs (multiples) en mode diffusion .        

(4) Relation plusieurs-à-plusieurs . Il est permis d'établir une boîte aux lettres publique , afin que plusieurs processus puissent envoyer des messages à la boîte aux lettres ; ils peuvent également prendre leurs propres messages de la boîte aux lettres.

3. Plusieurs problèmes dans la mise en œuvre du système de livraison de messages

3.1 Lien de communication

Pour que la communication ait lieu entre le processus d'envoi et le processus de réception, un lien de communication doit être établi entre les deux. La première est la suivante : avant la communication, le processus d'envoi utilise une commande explicite "établir la connexion" (langage primitif) pour établir et supprimer .        

La deuxième méthode est que le processus d'envoi n'a pas besoin de demander explicitement d'établir un lien, mais n'a besoin que d'utiliser la commande d'envoi (langage primitif) fournie par le système, et le système établira automatiquement un lien pour celui- ci . Cette méthode est principalement utilisée dans les systèmes autonomes.

Selon la méthode de connexion du lien de communication, le lien de communication peut être divisé en deux types :

Lien de communication de connexion point à point , un lien à ce moment ne connecte que deux nœuds (processus);

②Les liens de connexion multipoints font référence à la connexion de plusieurs (n> 2) nœuds (processus) avec un seul lien.

Selon les différents modes de communication, les liens peuvent être divisés en deux types :

Un lien de communication unidirectionnel qui permet uniquement au processus émetteur d'envoyer des messages au processus récepteur ;

②La liaison bidirectionnelle permet non seulement au processus A d'envoyer des messages au processus B, mais permet également au processus B d'envoyer des messages au processus A en même temps.

3.2 Format du message

Dans certains systèmes d'exploitation, le message est dans un format de message de longueur fixe relativement court , ce qui réduit la surcharge de traitement et de stockage du message. Cette méthode peut être utilisée dans les systèmes de bureautique pour fournir aux utilisateurs une communication rapide de type note ; mais elle n'est pas pratique pour les utilisateurs qui souhaitent envoyer des messages plus longs. Dans certains systèmes d'exploitation, un autre format de message de longueur variable est adopté, c'est-à-dire que la longueur du message envoyé par le processus est variable . Le système doit payer plus de frais généraux lors du traitement et du stockage des messages de longueur variable, mais c'est pratique pour les utilisateurs. Ces deux formats de message ont leurs propres avantages et inconvénients, de sorte que dans de nombreux systèmes (y compris les réseaux informatiques), ils sont utilisés en même temps .

3.3 Méthode de synchronisation de processus

Quel que soit le processus d'envoi/réception, une fois le message envoyé/reçu, il existe deux possibilités d'envoi/réception ou de blocage.

(1) Le processus d'envoi est bloqué et le processus de réception est bloqué.

(2) Le processus d'envoi n'est pas bloqué et le processus de réception est bloqué.

(3) Ni le processus d'envoi ni le processus de réception ne sont bloqués.

3.4 Utilisation de la transmission de messages pour parvenir à l'exclusion mutuelle

Le processus d'envoi n'est pas bloqué et le processus de réception est bloqué

Plusieurs processus d'envoi et de réception s'exécutant simultanément partagent un mutex de boîte aux lettres, qui est initialisé comme un "message vide" sans contenu

Si un processus souhaite entrer dans une section critique, il doit d'abord demander à recevoir un message de la boîte aux lettres mutex. Si la boîte aux lettres est vide, le processus est bloqué ; s'il est reçu, il entre dans la section critique, après exécution, sort de la section critique et renvoie le message dans la boîte aux lettres.

Program mutualexclusion
Const n=…;//进程数
Procedure P(i:integer)
Var msg:message
Begin
Repeat 
	receive(mutex,msg)
<临界区>
Send(mutex,msg)
Forever
End

Begin/*主程序*/
Create_mailbox(mutex);
Send(mutex,null);
Parbegin
P(1);
P(2);
….
P(n)
Parend
end

4. Exemple de système de messagerie directe

Noyau : file d'attente du tampon de messages, envoi de primitives, réception de primitives

4.1 Mécanisme de communication de file d'attente de tampon de messages

(1) Principe : Le système gère un groupe de tampons, et chaque tampon peut stocker un message . Lorsque le processus d'envoi veut envoyer un message, il doit d'abord demander un tampon au système, puis y écrire le message, puis connecter le tampon à la file d'attente de tampons de messages du processus de réception. Le processus de réception peut détacher le tampon de messages de la file d'attente de tampons de messages à un moment approprié, lire le message et libérer le tampon.

(2) Structure des données : Éléments de données étendus liés à la communication dans le tampon de messages et le circuit imprimé de processus :

//消息缓冲区
type message buffer=record
 sender  ;发送进程的标识符  
 size    ;消息长度
              text    ;消息正文         
       next    ;指向下一个消息缓冲区的指针
    end

Les éléments de données ajoutés par PCB sont les suivants (le sémaphore qui opère sur la file d'attente des messages et réalise la synchronisation) :

type processcontrol block=record
		mq; 消息队列队首指针
        mutex; 消息队列互斥信号量
        sm; 消息队列资源信号量
	end 

4.2 Envoyer des primitives

Avant d'envoyer un message à l'aide de la primitive d'envoi, le processus d'envoi doit d'abord configurer une zone d'envoi a dans son propre espace mémoire, comme illustré à la Figure 2-12, et remplir le texte du message à envoyer, l'identifiant du processus d'envoi, la longueur du message , etc. Entrez-le, puis appelez la primitive d'envoi pour envoyer le message au processus cible (de réception).

La primitive d'envoi s'applique d'abord à un tampon i selon la longueur de message a.size définie dans la zone d'envoi a, puis copie les informations dans la zone d'envoi a vers le tampon i. Afin d'accrocher i sur la file d'attente de messages mq du processus récepteur, obtenez d'abord l'identifiant interne j du processus récepteur, puis accrochez i sur j.mq. La file d'attente étant une ressource critique, les opérations d'attente et de signal doivent être effectuées avant et après l'opération d'insertion.

procedure send(receiver, a)
     begin
        getbuf(a.size,i);                         根据a.size申请缓冲区;
        i.sender∶   =a.sender;  将发送区a中的信息复制到消息缓冲区之中;
        i.size∶   =a.size;
        i.text∶   =a.text;
        i.next∶   =0;
       getid(PCB set, receiver.j);   获得接收进程内部标识符;
       wait(j.mutex);
       insert(j.mq, i);   将消息缓冲区插入消息队列;
       signal(j.mutex);
       signal(j.sm);
    end 

4.3 Recevoir des primitives

procedure receive(b)
   begin
    j∶   =internal name; j为接收进程内部的标识符;
    wait(j.sm);
    wait(j.mutex);
    remove(j.mq, i); 将消息队列中第一个消息移出;
    signal(j.mutex);
    b.sender∶   =i.sender; 将消息缓冲区i中的信息复制到接收区b;
    b.size∶   =i.size;
    b.text∶   =i.text;
  end 

Un exemple d'espace d'adressage système est illustré dans la figure (il y a deux messages dans la file d'attente des messages) :

Six, fil

Auparavant, un processus était utilisé comme unité de base qui possédait des ressources et était planifié (en cours d'exécution) de manière indépendante, mais a ensuite découvert une unité de base plus petite, thread , qui peut améliorer le degré d'exécution simultanée de programmes.

7. Quelques exemples

Enfin, utilisez quelques exemples pour terminer le deuxième chapitre ~

Comme le montre la figure, essayez le sémaphore pour réaliser la synchronisation de ces six processus

Conseils : Le même processus applique différents sémaphores à différents processus.

Utiliser le fonctionnement PV pour résoudre le problème des pilotes et des conducteurs

Conseils : Il s'agit d'un problème de synchronisation, il n'y a pas de concurrence pour les ressources et l'attention principale doit être portée sur l'ordre d'exécution. Fermez la porte -> conduisez, garez-vous -> ouvrez la porte

 Il y a une assiette vide sur la table et un maximum d'un fruit est autorisé. Papa peut mettre une pomme ou une orange dans l'assiette, le fils attend pour manger l'orange dans l'assiette et la fille attend pour manger la pomme.     

Essayez les opérations P et V pour réaliser la synchronisation des trois processus concurrents de père, fils et fille.

Noyau : Définissez trois sémaphores S, So, Sa, les valeurs initiales sont respectivement 1, 0, 0. Indiquez respectivement si vous pouvez mettre des fruits dans l'assiette, si vous pouvez prendre des oranges et si vous pouvez prendre des pommes.

Je suppose que tu aimes

Origine blog.csdn.net/weixin_51426083/article/details/129967342
conseillé
Classement