• Aucun résultat trouvé

Quelques notions de base de la programmation concurrente

Les notions pr´esent´ees dans cette section sont inspir´ees des chapitres 5 et 6 du livre de Stallings [31].

4.2.1 Le processus

Un processus est un programme en cours d’ex´ecution. De fa¸con plus pr´ecise, il peut ˆetre d´efini comme :

– un ensemble d’instructions `a ex´ecuter, pouvant ˆetre dans la m´emoire morte, mais le plus souvent charg´e depuis la m´emoire de masse vers la m´emoire vive ;

– un espace d’adressage en m´emoire vive pour stocker la pile, les donn´ees de travail, etc. ; – des ressources telles que les ports r´eseau.

L’ex´ecution d’un processus dure un certain temps, avec un d´ebut et parfois une fin. Un processus peut ˆetre d´emarr´e par un utilisateur, par l’interm´ediaire d’un p´eriph´erique ou par un autre processus. La plupart des syst`emes d’exploitation fournissent une fonction standard de cr´eation de processus, `a l’exemple de la commande spawn dans les syst`emes de type UNIX. Cette fonction permet `a un processus de donner naissance `a un nouveau processus qui est sa copie conforme, par exemple en vue de r´ealiser un second traitement parall`element au premier. Apr`es la cr´eation d’un processus enfant par un processus parent, le processus fils continue `a ex´ecuter le mˆeme programme que son processus parent, `a partir du point d’appel de la commande de cr´eation du processus. Il existe une filiation dans les processus, le cr´eateur d’un nouveau processus est appel´e le p`ere et le nouveau processus, le fils. Tous les attributs syst`eme du p`ere (par exemple les droits sur le syst`eme de fichier) sont transmis au fils. Au d´emarrage d’un programme concurrent, un seul processus existe. Tous les autres processus qui peuvent exister au cours de l’ex´ecution du programme sont des descendants directs ou indirects du premier processus.

4.2.2 L’entrelacement des s´equences

Lorsque deux programmes s’ex´ecutent en mˆeme temps et en parall`ele, nous pouvons consid´erer que nous avons deux s´equences d’instructions parall`eles. Cependant, il se peut que le rythme de progression des s´equences ne soit pas constant dans le temps. La variation dans la progression des programmes est sans importance si les deux programmes sont ind´ependants. C’est-`a-dire que les r´esultats et la progression d’un programme ne sont pas affect´es par les instructions ex´ecut´ees par l’autre programme. Cependant, si les deux programmes sont d´ependants, il faut pr´eciser si une instruction d’un programme a eu lieu avant ou apr`es une instruction de l’autre programme. Il faut alors tenir compte de la progression stricte dans le temps des deux programmes. On peut ainsi ˆetre amen´e `a combiner les deux s´equences en une seule, tenant compte de la progression relative des deux s´equences. La s´equence produite va consister en un entrelacement des deux s´equences originales. Exemple : consid´erons un programme concurrent avec deux processus P1 et P2, avec chacun deux instructions. Comme on peut voir dans la

P1 P2 S1 S3 S2 S4 s´equences possibles S1 → S2 → S3→ S4 S1 → S3 → S2→ S4 S1 → S3 → S4→ S2 S3 → S1 → S2→ S4 S3 → S1 → S4→ S2 S3 → S4 → S1→ S2

Table 4.1 – S´equencement des instructions

4.2.3 La synchronisation

Dans la programmation concurrente, il y a des m´ecanismes qui permettent de synchroniser les processus pour ´eliminer des s´equences non souhait´ees. La synchronisation implique que la progression d’un processus est ´eventuellement contrˆol´ee par un autre. Cela implique l’arrˆet ´eventuel d’un processus pendant que l’autre ex´ecute des actions particuli`eres. Mˆeme sur une machine avec un seul processeur, l’ex´ecution concurrente de processus nous force `a consid´erer tous les entrelacements possibles. En effet, on ne sait pas `a quel moment particulier un proces- sus va ˆetre interrompu pour permettre la reprise d’un autre processus. Le hasard peut faire en sorte qu’on obtienne n’importe laquelle des s´equences possibles. Le besoin de synchronisation est toujours pr´esent.

Plusieurs m´ecanismes peuvent ˆetre utilis´es pour impl´ementer la synchronisation : – l’ajout de code dans les programmes

– l’ajout mat´eriel, instruction test-and-set1 – l’utilisation des s´emaphores

– l’utilisation de la r´egion critique – l’utilisation des moniteurs

Le mod`ele de Russo et Sabelfeld que nous pr´esentons plus loin utilise les s´emaphores. Pour cette raison, nous allons donner plus de d´etails sur leur fonctionnement.

1. L’instruction test-and-set est une instruction atomique utilis´ee en informatique pour ´ecrire dans un emplacement m´emoire et retourner la valeur d’origine de cet emplacement. Elle permet de prot´eger un espace de la m´emoire en cas d’acc`es concurrents : si plusieurs processus tentent d’acc´eder `a la mˆeme m´emoire et si un processus est en train d’effectuer un test-and-set sur cette mˆeme m´emoire, alors aucun autre processus ne peut commencer un autre test-and-set jusqu’`a ce que le premier processus soit termin´e.

4.2.4 Les s´emaphores

Un s´emaphore est une variable enti`ere `a laquelle on acc`ede seulement par deux op´erations standards et atomiques, P () et V (). Selon le langage de programmation, il existe une mani`ere de d´eclarer et d’initialiser les s´emaphores. Les op´erations P et V sont aussi appel´ees wait pour P et signal pour V . Les d´efinitions classiques et standards de wait et signal pour un s´emaphore S sont :

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

L’appel de wait(S) d´ecr´emente la valeur de S et bloque le processus appelant. L’identifiant du processus est sauvegard´e dans la liste d’attente du s´emaphore si elle n’est pas vide, c’est- `

a-dire., si la valeur de S est sup´erieure `a z´ero. L’appel de signal(S) incr´emente la valeur de S et d´ebloque le premier processus de la liste d’attente.

`

A l’ex´ecution du programme, la modification de la valeur enti`ere du s´emaphore dans wait et signal est effectu´ee de mani`ere indivisible. Donc, lorsqu’un processus modifie la valeur du s´emaphore, aucun autre processus ne peut simultan´ement modifier le mˆeme s´emaphore. De plus, dans l’op´eration wait, le test de l’expression de la garde de la boucle (S <= 0) et la modification de la valeur (l’instruction S := S − 1) doivent s’ex´ecuter sans interruption, d’une mani`ere atomique.

Si le processus P1 de l’exemple du paragraphe4.2.2doit attendre que le processus P2 atteigne

un certain objectif avant une certaine action, P1 et P2 peuvent partager un s´emaphore S

initialis´e avec la valeur z´ero. Lorsque P2 atteint son objectif, il ex´ecute wait(S) qui le bloque.

Lorsque P1atteint l’endroit o`u il faut attendre, il ex´ecute signal(S). Quel que soit le processus

qui appelle le s´emaphore en premier, P1 va attendre que P2 r´ealise l’objectif initialement fix´e.

La figure4.1pr´esente un exemple d’utilisation de deux s´emaphores a et b sur les deux processus P1 et P2 pr´ec´edents. La commande wait(a) (respectivement wait(b)) bloque le processus si

a (respectivement b) vaut z´ero, sinon, la variable a (respectivement b) est d´ecr´ement´ee d’une unit´e. La commande signal(a) (respectivement signal(b)) incr´emente a (respectivement b) d’une unit´e. Comme r´esultat le nombre de s´equences est r´eduit `a une unit´e.

Notons que selon la d´efinition, la valeur du s´emaphore n’est jamais n´egative. Une implantation peut cependant faire que la valeur devienne n´egative. C’est pourquoi il est interdit d’exami- ner ou de modifier la valeur d’un s´emaphore. Normalement, un s´emaphore est initialis´e `a z´ero. Certains langages ou environnements permettent de sp´ecifier ou de modifier la valeur d’initialisation.

Figure 4.1 – Synchronisation par des s´emaphores tir´ee de [31]