340 likes | 507 Views
Travailler avec des processus. Mémoire partagée, communication et synchronisation. Rappels. On peut faire plusieurs processus à partir d’un père Clonage : fork() Faire attention aux variables : Toutes celles déclarées avant le fork sont visibles aux 2
E N D
Travailler avec des processus Mémoire partagée, communication et synchronisation
Rappels • On peut faire plusieurs processus à partir d’un père • Clonage : fork() • Faire attention aux variables : • Toutes celles déclarées avant le fork sont visibles aux 2 • Toutes les modifications après sont indépendantes
Rappels • Utilisation courante : fork()+exec() • On fait deux programmes différents • On les exécute en parallèle • Ex : le prog principal est un serveur, le sous prog se charge de la communication avec un client…
Rappels sur la communication • Une fois la séparation des processus, on communique avec une mémoire partagée. • Lors de la création du fils (avec exec), il est possible de lui passer des paramètres (rappelez vous du tableau de fou…), comme l’id de la mémoire partagée… • Possibilités : Utilisation mémoire partagée Création mémoire partagée Utilisation mémoire partagée
Rappels fin • Donc pour utiliser une mémoire partagée, il faut la créer • int idShm = shmget (key, sizeof(Float), IPC_CREAT|0666) ; • On peut ensuite l’utiliser : • float * maVar = (float *) shmat (idShm, NULL, 0) ; • Après il est possible de mettre des choses dans la variable • Et il est bien sûr possible de lire le contenu…
Notion de ressources • Un système d’exploitation gère l’accès à des ressources. Il existe différents types de ressources : • Non critiques : peuvent être utilisées conjointement par un nombre quelconque de processus (uniquement en lecture). • Critiques: ne peuvent être utilisées que par un nombre limité de processus à un instant donné. • Critiques exclusives : ne peuvent être utilisées que par un seul processus à un instant donné.
Ressource critique • Une ressource est qualifiée de critique exclusive si : • "il est physiquement impossible que plusieurs processus l’utilisent simultanément (p.ex. un marteau). • "il est dangereux (risque d’incohérence) que plusieurs processus l’utilisent simultanément (p. ex. un cahier).
Exemple de problèmes • Expédition de messages complets à une console • Expédition d’une suite de lignes à une imprimante • Utilisation d’un dérouleur de bandes magnétiques • Utilisation d’un fichier en écriture • Utilisation d’une table en mémoire principale, en modification • Utilisation conjointe, par plusieurs processus, d’un traceur de courbes • réservation de places dans les trains ou les avions, par plusieurs agences de voyage simultanément
Notion de région critique • Région critique ou section critique • Une section critique d’un processus correspond à une partie de son code pendant l’exécution duquel il doit se voir attribuer de façon exclusiveune ressource critique exclusive spécifique. • Il faut donc trouver une manière de protéger une portion du code : celle qui s’occupe de la ressource critique.
Notre section critique • Par soucis de simplicité, on utilisera une ressource critique simple : un tableau. • Mais tout ce qu’on verra sera applicable sur d’autres ressources (imprimante, écran…)
Le problème • Il faut avoir un mécanisme qui empêche d’avoir plus de X processus qui utilisent la ressource
Solution 1 • Utiliser une variable booléenne (libre/occupé) : Tant que marqueur != libre; FinTantQue marqueur = occupé; RC; marqueur = libre; Mais… • Si deux processus testent à la suite la condition du tant que, on aura deux processus qui utilisent la ressource critique
Solution 2 • Utiliser une variable entière : Tant que tour != monNum; FinTantQue RC; tour = 3-monNum;//passe au suivant pour deux processus (3-2=1;3-1=2) Mais… • Si un processus plante en dehors de la section critique, plus personne n’y rentrera…
Solution 3 • Mix des deux solutions : • Utiliser deux variables : • Un tableau de booléen du nombre de processus • Un identifiant (un numéro) oùça[moi]:=dedans; Tantque oùça[3-moi]!=dehors; finTantQue RC; oùça[moi]:=dehors;
Solution 3 oùça[moi]:=dedans; Tantque oùça[3-moi]!=dehors; finTantQue RC; oùça[moi]:=dehors; • Mais… • On peut bloquer indéfiniment sur le tantque…
Solution 4,5,6… • Je ne veux pas vous embrouiller plus, mais pour info, y’a eu : • Algorithme de Dekker • Algorithme de Peterson • Solution avec XW • Solution avec TST • … • Enfin, il y a eu Dijkstra qui simplifia (Hum…) le problème
P(S) • functionP(semaphore sem) { disable_interrupt; sem.K = sem.K-1; if (sem.K < 0) { L.suivant = processus_courant; processus_courant.state= bloque; reordonnancement = vrai; } enable_interrupt; }
V(S) • functionV(semaphore sem) { disable_interrupt; sem.K=sem.K+1; if (sem.K <= 0) { processus_reveille= L.tete; processus_reveille.state = prêt; reordonnancement = vrai; } enable_interrupt; }
L’utilisation des sémaphores var mutex : sémaphore; process p(moi:pNum); begin whiletrue do begin P(mutex) R.C. V(mutex); end; end {de p}
Les sémaphores Exclusion mutuelle • Initialisation du sémaphore à 1 • Initialisation du sémaphore avec un nombre égal au nombre max de processus autorisés Exclusion générale
Les sémaphores • Bon, ça c’est pas trop difficile… • Toujours la même chose : P(mutex) R.C. V(mutex); • Mais d’autres problèmes plus complexes… • Synchroniser deux processus • Communiquer entre deux processus
On complique un peu • On veux que la solution soit compatible avec la précédente solution, i.e. utiliser les sémaphores • Le problème du rendez-vous simple: • Pb ne peut passer le point de synchronisation Sb que quand Pa aura auparavant passé le point de synchronisation Sa. • "Cas 1 : Pb arrive en Sb et Pa n’est pas encore passé en Sa : il attend. • "Cas 2 : Pb arrive en Sb alors que Pa est déjà passé en Sa : il continue.
Remarques • Dans certain ouvrage, on trouve • P() Wait() • V() Signal() • P() est parfois bloquant • V() n’est jamais bloquant
Solution process Pb; begin repeat Avant; P(sem); Après; until false end; { de Pb } process Pa; begin repeat Avant; V(sem); Après; until false end; { de Pa }
Problème suite • Un grand classique : Producteur/Consommateurs
Producteur Consommateur • Définition du problème : • Un producteur ne peut produire que quand il reste de la place • Un consommateur doit attendre qu’une valeur soit produite • Un consommateur consomme tant qu’il y a des valeurs… • D’où des problèmes : • Empêcher les consommateur de lire dans le tampon quand il n’y a rien dedans • Empêcher les producteur de produire quand il n’y a plus de place
Solution • 3 choses a définir : • Nombre de sémaphores et leurs initialisations • Processus Producteur • Processus Consommateur
Producteur Consommateur • Initialisation des sémaphores : Const N = 8; {nb cases} Var inDex, exDex : Case init 0; mutexProd, mutexCons : semaphore init 1; nbPlein : semaphore init 0; nbVide : semaphore init N; T : array [Case] of Portion;
Producteur process Producteur; begin repeat Produire; P(nVide); P(mutexProd); {insérer dans le tampon}; V(mutexProd); V(nPlein); until false end; { de Producteur }
Consommateur process Consommateur; begin repeat P(nPlein); P(mutexCons); {extraire du tampon}; V(mutexCons); V(nVide); Consommer; until false end; { de Consommateur }
Producteur/Consommateur process Producteur; begin repeat Produire; P(nVide); P(mutexProd); {insérer}; V(mutexProd); V(nPlein); until false end; { de Producteur } process Consommateur; begin repeat P(nPlein); P(mutexCons); {extraire}; V(mutexCons); V(nVide); Consommer; until false end; { de Consommateur }
En C++ • Il faut utiliser la librairie zthread