Devoir Surveillé en Systèmes d’exploitation et Programmation Concurrente

Page 1 sur 7Lecteur de document UniversityLib

Devoir Surveillé en Systèmes d’exploitation et Programmation Concurrente

Systèmes d’exploitation, Programmation Concurrente · exam

Voir tous les documents en programmation

Ecole Nationale des Sciences de l’Informatique

A. U. : 2012/2013

Devoir Surveillé

Systèmes d’exploitation Programmation Concurrente

Classes

: II2

Date

: 16/11/2012

Durée

: 2h00

Nb. Pages

: 4

Documents : Non autorisés

Enseignants: F. Najjar, M. S. Ouerghi, Z. Bouyahia, A. Dhraif , M. Nasri, & S. Mtibaa

Note: On demande des réponses brèves mais claires, précises et concises

Questions de Cours – 8 x 1 point

(3 lignes max.)

1. Qu’est ce qu’un multithreading ? et quelle est

la différence avec

la

multiprogrammation?

2. Quelles sont les principales similarités/différences entre un processus et un thread ?

Dans une application qui partage des données en mémoire, faut-il privilégier les

processus ou les threads ?

3. Décrire ce qu’est un TCB (Thread Control Bloc) en vous inspirant du contenu d’un

PCB (Process Control Bloc ou encore un Descripteur de Processus).

4. Que se passe-t-il au niveau du noyau système Unix, lorsqu’il se charge de la de

création d’un nouveau processus ?

5. Qu’est ce qu’une ressource critique et quelles sont propriétés que doit assurer un

système d’exploitation pour autoriser son accès ?

6. Dire quels sont les quatre moyens de synchronisation pour les threads ?

1

7. A) Définir les trois états d’un processus : Eligibles, Elu et Bloqués

B) Expliquer ce qui se passe lors des transitions : Activation, Préemption, Attente et

Fin d’attente. Indiquer quand est-ce que ces transitions auront lieu.

Programmation concurrente

12 points

Exercice 1 (2 points)

Combien de processus engendre l’exécution du programme C suivant et en donner

l’arborescence.

include < unistd .h>

int main ( void )

{

fork () && ( fork () || fork () );

sleep (2);

return 0; }

Exercice 2 (3 points)

Soient les deux processus PA et PB partageant une variable k initialisée comme suit :

public int k=1;

Processus PA

int main (){

int i;

Processus PB

int main (){

Publicité

int j;

i=k;

i=i+1;

k=i;

printf("k=%d\n",k);

...

}

j=k;

j=j+4;

k=j;

printf("k=%d\n",k);

...

}

2

1) Les résultats suivants sont-ils possibles, oui ou non ? Justifiez vos réponses ?

Processus PA Processus PB

R1

R2

R3

K=2

K=2

K=5

K=2

K=6

K=2

2) (Bonus –1 point) En donnez deux autres possibilités correctes d’exécutions

concurrentes?

Exercice 3. – Reader/Writer Multithread (7 points –1 + 1,5 + 1,5 + 2 +1)

Considérez les deux morceaux de code suivants. Deux threads exécutent respectivement les

fonctions writer_thread() et reader_thread(), et partagent la variable pointer.

int *pointer = NULL;

void * writer_thread() {

while (1) {

if (pointer == NULL) {

pointer = malloc(sizeof(int));

*pointer = rand();

//fonction dans stdlib.h pour recevoir une valeur aléatoire

}

}

}

void *reader_thread() {

while (1) {

if (pointer != NULL) {

printf("pointer = %d\n", *pointer);

free(pointer);

pointer = NULL;

}

}

}

1) En exécutant le programme qui crée deux threads ayant les fonctions précédentes, une

erreur “Erreur de segmentation” apparaît au bout d’un certain temps. D’où provient cette

erreur ? Expliquer.

2) Résolvez ce problème en modifiant le programme par l’ajout d’un sémaphore. On

supposera que le sémaphore est initialisé dans le thread principal.

Publicité

3) Peut-on résoudre ce problème sans utilisation d’un sémaphore ou de tout autre

mécanisme de synchronisation? Même question si on exécute plusieurs paires écrivain

(fonction writer_thread()) et lecteur (fonction reader_thread()) ?

3

4) Nous proposons d’utiliser une variable conditionnelle pour régler ce problème. La

variable conditionnelle doit servir, d’une part à garantir l’exclusion mutuelle entre les

accès à pointer (rôle joué par le sémaphore utilisé dans les questions précédentes), et

d’autre-part à alerter l’autre thread d’une modification de la variable pointer. Modifiez les

fonctions en conséquence.

5) Ecrire le thread principal, en se basant sur ce qui précède.

Annexe: Prototype de quelques fonctions manipulant les Posix threads

Thread :

int pthread_create(pthread_t tid, const pthread_attr_t attr, void (routine)(void), void arg);

-

  • void pthread_exit(void* status);

-

  • pthread_t pthread_self(void);

Verrou :

int pthread_join(pthread_t thread, void **status);

int pthread_mutex_init(pthread_mutex_t mutex, const pthread_mutex_attr attr);

int pthread_mutex_destroy(pthread_mutex_t *mutex);

int pthread_mutex_lock(pthread_mutex *mutex);

int pthread_mutex_unlock(pthread_mutex *mutex);

-

-

-

-

Sémaphore:

-

-

-

-

int sem_init(sem_t *sem, int pshared, unsigned int valeur) ;

int sem_wait(sem_t *sem) ;

int sem_post(sem_t *sem) ;

int sem_destroy(sem_t *sem) ;

Condition :

-

-

-

-

-

int pthread_cond_init(pthread_cond_t cond, pthread_cond_attr attr);

int pthread_cond_wait(pthread_cond_t cond,pthread_mutex_t mutex);

int pthread_cond_signal(pthread_cond_t *cond);

int pthread_cond_broadcast((pthread_cond_t *cond);

int pthread_cond_destroy((pthread_cond_t *cond);

4

Proposition de correction

DS SE&PC

Du 16/11/2012

Questions de cours (8 points – 8*1point/question)

1) Multithreading : exécution concurrente/parallèle de plusieurs

l’intérieur d’un même processus alors que

Publicité

l’exécution concurrente de plusieurs processus sur un monoprocesseur.

threads à

la multiprogrammation c’est

2) Un processus est une unité de structuration, défini techniq. par un seg. Code, un

seg. Data et un seg. Pile d’exécution et un contexte alors qu’un thread (ou encore

processus léger) est une unité d’exécution qui partage avec tous les autres

threads d’un même processus l’espace d’adressage mémoire mais il ne contient

que sa pile d’exécution, son CO, … On privilégie les threads par rapport aux

processus afin de gagner en performance en particulier la commutation est moins

coûteuse.

3) TCB :

4) Lors de la création d’un processus

5) RC est une ressource partagée où le nombre de points d’accès est égal { un et

donc à accès exclusif . Un SE doit assurer le contrôle d’accès exclusif via par eg. les

mutex.

6) Quatre moyens de synchronisation pour les threads : 1) pthread_join(), 2) les

mutex, 3) les sémaphores, et 4) les variables conditionnelles (l’équiv. De

moniteur)

Programmation concurrente

Exercice 1 (2 points)

Le processus père engendre dans l’ensemble 3 autres processus. En effet, comme dans une

instruction (a && b), b n’est évaluée que si l’´evaluation de a donne Faux (c-à-d 0), de même,

dans une instruction (a || b), b n’est évaluée que si l’´evaluation de a ne donne pas 0. Donc,

dans fork() && b seulement le père exécute b, et dans fork() || b seulement le fils exécute b.

Exercice 2 (3 points + 1 point bonus)

5

1) Si on numérote : I1, I2,I3,I4 les instructions du Processus PA et J1, J2,J3, J4

instructions du Processus PB : I1, J1, I2, J2, J3, I3, I4, J4 -> R1 possible (et

non correcte car n’appartient pas à l’ens. Des résultats générés par PA ; PB

(2, 6) ou encore PB ;PA (6, 5)).

(entrelacements se terminant par : J3, I3, I4, J4 ou , J3, I3,J4,I4) I1, J1, I2, I3,

I4, J2, J3, J3, J4 -> R2

R3aucun entrelacement possible !!

2) PB ;PA  K= 6 (PA) K=5 (PB) possible et correcte et une autre possible (non correcte) (5, 5) c-

à-d I1 ; I2 ; I3 ; J1 ;J2 ;J3 ;J4 ; I4.

Exercice 3: (7 points –1+1,5+1,5+2+1)

Question 1

En exécutant ce programme, une erreur “Erreur de segmentation” apparaît au bout d’un certain

temps. D’où provient cette erreur ?

Réponse 1

Le lecteur peut effectuer l’appel à free() pendant que l’écrivain est bloqué dans random().

Question 2

Résolvez ce problème en modifiant le programme par l’ajout d’un sémaphore. En dire la valeur

initiale de ce sémaphore dans le programme principal .

Réponse 2

void writer_thread() {

while (1) {

sem_wait();

if (pointer == NULL) {

pointer = malloc(sizeof(int));

*pointer = random();

}

sem_post();

}

Publicité

}

void reader_thread() {

while (1) {

sem_wait();

if (pointer != NULL) {

printf("pointer = %d\n", *pointer);

free(pointer);

pointer = NULL;

6

}

sem_post();

}

}

Question 3

Peut-on résoudre ce problème sans utilisation d’un sémaphore ou de tout autre mécanisme

d’exclusion mutuelle? Même question si on exécute plusieurs paires écrivain (fonction

writer_thread()) et lecteur (fonction reader_thread()) ?

Réponse 3

Oui, l’écrivan peut utiliser une variable locale pour l’allocation et l’initialisation, puis

modifier pointer en une instruction (l’écriture en mémoire étant atomique).

Non dans le cas de plusieurs paires écrivain-lecteur (fuite mémoire), une exclusion

mutuelle pour séquentialiser et séparer les allocations/libérations est nécessaire, car la

communication de l’adresse à libérer se fait via une unique variable pointer.

Question 4

Nous proposons d’utiliser une variable de condition pour régler ce problème. La variable de

condition doit servir, d’une part à garantir l’exclusion mutuelle entre les accès à pointer (rôle joué

par le sémaphore utilisé dans les question précédentes), et d’autre-part à alerter l’autre thread

d’une modification de la variable pointer. Modifiez le programme en conséquence.

Réponse 4

void writer_thread(){ //Le producteur

while (1){

pthread_mutex_lock(&mut);

if (pointer != NULL)

pthread_cond_wait(cond, mut);

pointer = malloc(sizeof(int));

*pointer = random();

pthread_cond_signal(cond);

pthread_mutex_unlock(&mut);

}

}

void reader_thread(){ //Le consommateur

while (1) {

pthread_mutex_lock(&mut);

if (pointer == NULL)

pthread_cond_wait(cond, mut);

printf("Valeur: %d\n", *pointer);

free(pointer);

pointer = NULL;

condition_signal(cond);

pthread_mutex_unlock(&mut);

}

}

7