Vous êtes sur la page 1sur 26

Chapitre 2

Fondements pour la programmation


des systmes temps rel et embarqus

Elments de la norme POSIX

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


42

1. Programmation concurrente

z Une application TRE = ensemble dactivits concurrentes ventuellement rparties

z Programmation concurrente permet


p
- Expression et manipulation
p (cration,
( , destruction)) dentits concurrentes
(appeles tches, processus ou threads)
- Mise en place de moyens de communication et synchronisation entre tches
- Abstraction de lexcution relle des tches sur une architecture mono ou
multi processeur

z Programmation temps rel =


programmation concurrente + prise en compte de contraintes de temps
* Lire le temps (horloge)
* Fixer/modifier la priorit de tches
* Supprimer certains aspects du langage pour le rendre dterministe.

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


43

1
Problmes inhrents la programmation concurrente (1)

z Problme de sret (safety) : Interboclage


Demande
de ressource

R1 R2
T1 R1 R1

R2 R1
R2
T2
Interblocage

Ressources : R1 et R2 Prio1 < Prio2

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


44

Problmes inhrents la programmation concurrente (2)

z Problme de vivacit (liveliness): Famine, non terminaison

- Suite une mauvaise conception deux processus narrivent jamais se


synchroniser.
Par exemple, pour rparer un chauffe-eau lectrique, le plombier exige que
llectricit soit aux normes (et il faut donc lintervention de llectricien). De son
ct, llectricien exige de ne faire les travaux que lorsque les problmes de fuite
deau seront rsolus (il faut donc lintervention pralable du plombier).

- Suite une mauvaise conception, un groupe de tches saccaparent une


ressource et empchent dautres tches de les utiliser.

z Problme de reproductibilit des erreurs


Lorsque plusieurs tches sexcutent en parallle, le nombre de comportements
possibles devient trs lev. Ainsi si une erreur survient, il est difficile de reproduire
cette erreur afin de comprendre son origine.

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


45

2
2. Gnralits sur la manipulation de tches

z Processus vs tche
- Un processus possde son propre espace dadressage. Il sexcute sur sa propre
machine virtuelle.
- Lee syst
systme
e dexploitation
d e p o tat o met
et e
en p
place
ace les
es mcanismes
ca s es de p
protection
otect o
inter processus.
- Le partage de mmoire entre processus est soit impossible, soit fait de manire
explicite par des appels systme.
- Une tche partage son espace dadressage avec dautres tches (mais ce nest
pas obligatoire).
- Le programmeur doit mettre en place manuellement les mcanismes de
protection inter tches.

z Processus vs tche vs thread


- En Ada on parle de tche
- En Java et dans la norme Posix, on parle de Process et thread.
- Un process Posix contient un ou plusieurs threads.

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


46

z Tches indpendantes
- Deux tches sont indpendantes si lexcution de lune ninflue pas sur lautre.

z Tches en coopration
- Deux tches sont en coopration si elles mnent un travail commun ncessitant
synchronisation et/ou communication.

z Tches en comptition
- Deux tches sont en comptition si accdent des ressources partages en exclusion.

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


47

3
Etats dune tche

Inexistante

Cre Termine

Prte Active

Bloque

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


48

Ecriture et dmarrage dune tche

z Quatre possibilits

- Dclaration explicite de tches grce aux constructeurs du langage (Ada, Java)


- Utilisation des primitives fork et join
* fork cre un processus qui sexcute en // avec son pre
* join permet un pre dattendre la fin dexcution de son fils.
- Utilisation de blocs cobegin et parbegin
- Utilisation de coroutines

z Remarque

- Lorsquon veut crire des tches qui constituent une mme application, il faut
viter (si possible) dutiliser fork et join. Il faut utiliser les primitives de cration et
de manipulation de threads.

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


49

4
Exemple de tche avec Fork et Join
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define N 50
int main(void)
{ p
pid
d_t
t tab_p
tab pid[N];
d[ ]; // p
pid
d des fils
s
int status, i;
for (i=0; i<N; i++){
if ( ! (tab_pid[i] = fork()) ){
// le code du fils; ici un simple affichage et un repos de une seconde
printf("hello\n");
sleep(1);
exit();
}
}
// Seul le pre arrive ici car les 50 fils ont termin par exit ;
// Il attend leur terminaison
for (i=0; i<N; i++){
waitpid( tab_pid[i], &status, 0);
}
return 0;
}

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


50

Exemple de tche en Ada

task type Genre_De_Tache -- Spcification du type de tche


(param Integer);

t k body
task b d Genre_De_Tache
G D T h i is -- Corps du type
begin
loop
Put(Param);
end loop;
end Un_Genre_De_Tache;

Tache1 : Genre_De_Tache(1); -- Dclaration de deux tches avec le


Tache2 : Genre_De_Tache(12); -- type dfini prcdemment

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


51

5
3. Programmation concurrente en C avec la norme Posix
(cration et terminaison de thread)

z La norme POSIX 1003.c (1995) dfinit une API pour manipuler des tches appeles
threads (pthreads) avec le langage C.
z Les dfinitions lies aux threads se trouvent dans le fichier <pthread.h>
p

z Chaque thread a ses registres et sa pile dexcution. Mais tous les threads dun mme
processus partagent le mme espace virtuel, les mmes actions vnementielles, les
mmes descripteurs de fichiers et dautres ressources du processus.

Code Donnes Code Donnes Fichiers

Fichiers
Registre Registre Registre
Registre Pile
Pile Pile Pile

Fil
dexcution

Processus mono-thread Processus multi-thread

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


52

z Un thread (tche) est dfini, du point de vue programmeur, par son identifiant systme de
type pthread_t

z Une tche POSIX nest pas dfinie mais cre par un appel de la primitive pthread_create.
Lappel de pthread_create cre une nouvelle tche qui sexcute en parallle avec
celle
ll quii la
l cre.

int pthread_create ( pthread_t *thread, const pthread_attr_t *attr,
void *(*start_fnc)(void *), void *arg)

En cas de succs, la fonction renvoie la valeur 0. La nouvelle tche est lance


automatiquement aprs sa cration. En cas dchec de cration, la fonction renvoie un code
derreur.
- Largument attr indique les attributs de la tche. Il peut tre gal NULL.
- La
L fonction
f ti start_fnc estt lla premire
i fonction
f ti excute
t par lla t
tche
h quand
d celle-ci
ll i estt
dmarre.
- arg contient les paramtres passs une tche au moment de sa cration.

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


53

6
z Le type pthread_attr_t est dfini par les attributs de thread suivants :
typedef struct
{ int __detachstate; // indique si ce thread peut se synchroniser (par join)
// avec un autre
int __schedpolicy; // Politique dordonnancement du thread (FIFO, RR, Other)
struct __sched_param __schedparam; // Paramtres dordo du thread
// en gnral, il y a un seul paramtre : la priorit
int __inheritsched; // Attribut dhritage de la politique dordo du pre
int __scope; // indique la porte de la priorit du thread (en gnral,
// l
la priorit
i it estt globale
l b l au systme)
t )
size_t __guardsize; // Infos sur la pile dexcution
int __stackaddr_set; //
void *__stackaddr; // Adresse en mmoire de la pile dexcution du thread
size_t _stacksize; // Taille de la pile dexcution du thread
} pthread_attr_t;

z Terminaison de tche
- Une tche POSIX se termine soit en appelant explicitement la fonction pthread_exit ou
implicitement lorsque la fonction start-routine sachve
- Si le programme principal termine normalement, les tches Posix cres par celui-ci sont
termines par un appel implicite la fonction systme exit.
- Si lon veut terminer proprement un programme crant des tches Posix, il est ncessaire
dattendre la terminaison de celles-ci en utilisant la primitive pthread_join
int pthread_join(pthread_t th_a_attendre, void **tache_return);

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


54

z Autres primitives de manipulation de threads


- Initialisation dattributs de thread : pthread_attr_init
- Destruction dattributs de thread : pthread_attr_destroy
- Obtention de ladresse de pile de thread : pthread_getstackaddr
- Modification de ladresse de pile de thread : pthread_setstackaddr
- Obtention de la taille de pile de thread : pthread_getstacksize
- Modification de la taille de pile de thread : pthread_setstacksize
- Test dgalit de deux identifieurs de threads : pthread_equal
- Terminaison dun thread : pthread_exit
- Obtention du Pid de lappelant : pthread_self

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


55

7
Exemple de programme multi-tches

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void *affichCar(void *arg){
char c;
int k;
c = * (char *)arg;
for (k=1; k<50; k++){
putchar( c);
}
}

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


56

// Cration de deux tches identiques

int main(void)
{ char *leCar; int i;
pthread_t tache_Posix_B;
pthread_t tache_Posix_C;
leCar = (char*) malloc(1*sizeof(char)); *leCar = 'B';
pthread_create( &tache_Posix_B, NULL, affCar, (void*) leCar);
leCar = (char*) malloc(1*sizeof(char)); *leCar = 'C';
pthread_create( &tache_Posix_C, NULL, affCar, (void*) leCar);
for (i=0; i<100; i++){
putchar(Z');
}
pthread_j
p join (tache_Posix_B, NULL);
pthread_join (tache_Posix_C, NULL);
}

Si on ne met pas ces deux instructions, les deux tches B et C seront termines
peine cres (elles nauront pas le temps de sexcuter)

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


57

8
4. Synchronisation et communication inter-tches

z Diffrents mcanismes sont utilisables pour la synchronisation

- Interruptions (niveau hardware)

- Signaux
Si (
(ex. signaux
i Unix)
U i )

- Smaphores (mal utiliss les smaphores conduisent des interblocages)

- Moniteurs (mcanisme de haut niveau; vite certaines erreurs de conception)

- Autres : verrous

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


58

z Rappels sur les smaphores (Dijkstra 1965)


- Un compteur entier (S_CPT)
- Une file dattente S_Attente
- Deux oprations P et V et ventuellement dune fonction dinitialisation S_init

P(S) : // prend le smaphore; bloquant si smaphore dj pris


S_CPT --;
Si (S_CPT < 0) Alors
Bloquer l'appelant et le mettre dans la file S_Attente;
fin si

V(S) : // rend le smaphore; jamais bloquant


S_CPT ++;
Si (S
(S_CPT
CPT <=
< 0) Alors
Choisir un processus dans la file S_Attente,
le retirer de celle-ci et le dbloquer;
fin si

S_init(S, Val) : // initialise le compteur interne la valeur Val


S_CPT <-- Val;

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


59

9
Mutex de Posix pour lexclusion mutuelle

z Concepts et principes de base

- Un mutex est un smaphore binaire (initialis par dfaut 1) pouvant prendre un


des deux tats : "lock" (verrouill) ou "unlock" (dvrrouill)

- Un mutex est utilis pour protger laccs une ressource/section critique

- Un mutex ne peut tre partag que par des threads dun mme processus

- Un mutex ne peut tre verrouill que par un seul thread la fois.

- Un thread qui tente de verrouiller un mutex dj verrouill est suspendu jusqu' ce


que ce mutex soit dverrouill.

- Un mutex est une variable de type thread_mutex_t


thread mutex t

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


60

z Dclaration et initialisation dun mutex


- Il existe une constante PTHREAD_MUTEX_INITIALIZER de type thread_mutex_t permettant
une dclaration avec initialisation statique du mutex
pthread_mutex_t monMutex = PTHREAD_MUTEX_INITIALIZER;

- Un mutex peut galement tre initialis par un appel de la primitive


int pthread_mutex_init(pthread_mutex_t *mutex,
const pthread_mutexattr_t *mutexattr);
typedef struct { int __mutexkind; } pthread_mutexattr_t;
Avec une initialisation par dfaut, mutexattr vaut NULL
ex :pthread_mutex_init(&monMutex, NULL);
- Un mutex non utilis peut (doit) tre supprim par pthread_mutex_destroy
int pthread_mutex_destroy (pthread_mutex_t *mutex)

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


61

10
z Verrouillage dun mutex
- Un Mutex peut tre verrouill par la primitive pthread_mutex_lock
init pthread_mutex_lock(pthread_mutex_t *mutex);

* Si le mutex est dverrouill, il devient verrouill.


Si le mutex est verrouill, lappelant est bloqu jusqu ce que mutex soit verrouill.

- Une autre alternative au pthread_mutex_lock bloquant est le pthread_mutex_trylock


qui est non bloquant (qui vrrouille le mutex sil est dverrouill et qui renvoie une erreur
si le mutex est dj verrouill)
init pthread_mutex_trylock(pthread_mutex_t *mutex);

- Posix 1003.b de 1999 dfinit une version dattente de mutex temporise


p (ce
( qui
q limite
le blocage infini) :
int pthread_mutex_timedlock(pthread_mutex_t *mutex,
const struct timespec *abs_timeout)

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


62

z Dverrouillage dun mutex


- Un Mutex peut tre dverrouill par la primitive thread_mutex_lunock
init pthread_mutex_unlock(pthread_mutex_t *mutex);
* Si le mutex est dj dverrouill, il reste dverrouill.
* Si le mutex est verrouill,, un des threads en attente de ce mutex est dbloqu.
q
- Lopration de dverrouillage est toujours non bloquante pour lappelant.

z Autres oprations sur un mutex


- pthread_mutexattr_destroy : dtruit des attributs de mutex :
- pthread_mutexattr_getshared : dtermine si un mutex est partageable par des processus
- pthread_mutexattr_setshared : modifie
difi lattribut
l tt ib t de
d partage
t dun
d mutex
t
- pthread_mutexattr_init : initialise les attributs dun mutex

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


63

11
Exemple dutilisation de mutex
.../..
pthread_mutex_t monMutex = PTHREAD_MUTEX_INITIALIZER;
void LitRegistre(ValeurRegistre R){
int i; for (i=0; i<TAILLE_REGISTRE; i++) R[i] = LeRegsitre[i];
}
void EcritRegistre(ValeurRegistre R){
int i; for (i=0; i<TAILLE_REGISTRE; i++) LeRegsitre[i] = R[i];
}
void f(void){
int i, j; ValeurRegistre RLocal;
for(j=0; j < 1000000; j++){
pthread_mutex_lock( &monMutex );
g ( RLocal )
LitRegistre( ); Section
for(i=0; i<TAILLE_REGISTRE; i++){ RLocal[i] ++; } critique
EcritRegistre( RLocal );
pthread_mutex_unlock( &monMutex );
}
}

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


64

Smaphores de Posix
z Notion de smaphore Posix
- Un smaphore Posix est un smaphore compte pouvant tre partag par plusieurs
threads de plusieurs processus (selon les implmentations)
- Le compteur associ un smaphore peut donc prendre des valeurs plus grandes que 1
(
(contrairement
t i t un mutex)
t )
- La prise d'un smaphore dont le compteur est ngatif ou nul bloque l'appelant
- Les dfinitions ncessaires la manipulation de smaphore se trouvent dans le fichier entte
<semaphore.h>

z Dclaration et initialisation dun smaphore


- Un smaphore est une variable de type sem_t
- Un smaphore est initialis par la primitive :
int sem_init(sem_t *sem, int pshared, unsigned int valeur);
* si "pshared" vaut 0 le smaphore ne peut pas tre partag quentre tches dun mme processus
* si "pshared" nest pas gal 0, le smaphore peut tre partag entre plusieurs processus
* valeur dfinit la valeur initiale de ce smaphore (positif ou nul)

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


65

12
z Prise de contrle et libration de smaphore Posix
- Les deux oprations P et V sont implantes par :
int sem_wait(sem_t *sem);
int sem_post(sem_t *sem);

- Il existe galement une version non bloquante de la primitive P :


int sem_trywait(sem_t *sem);
qui retourne 0 si quand la prise est possible (et non bloquante) et qui retourne
EAGAIN sinon (dans le cas o l'appel normal serait bloquant)

- Posix 1003.b de 1999 dfinit une version de P temporise (ce qui limite le blocage infini) :
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);

z Autres oprations sur les smaphores


- destruction de smaphore : sem_destroy
- renvoi de la valeur courante du compteur dun smaphore : sem_getvalue
- tablissement dun lien entre un smaphore nomm et un thread : sem_open
- rupture du lien entre un smaphore et un thread : sem_close

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


66

Variables conditionnelles de Posix

z Objectifs
- Les variables conditionnelles servent mettre un thread en attente de la satisfaction dune
condition (dpassement dun seuil de temprature par exemple) qui dpend de ltat dune
variable p
partage.
g

- Les variables conditionnelles sont utilises conjointement avec les mutex. Chaque variable
conditionnelle est lie un mutex qui la protge.
- Avant de tester une variable conditionnelle, le thread doit verrouiller laccs la variable par
le mutex associ cette variable.
- Quand un thread se bloque, par pthread_cond_wait, en attente de la satisfaction dune
condition, le mutex associ la variable conditionnelle est automatiquement libr par le
systme pour permettre un autre thread de rendre la condition vraievraie.
- Quand un thread est rveill, suite un pthread_cond_signal ou pthread_cond_broadcast,
le mutex est toujours en position verrouill (le thread rveill doit donc le dverrouiller).

- Les variables conditionnelles sont utilises pour la signalisation pas pour lexclusion mutuelle.

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


67

13
z Dclaration, initialisation et manipulation de variable conditionnelle
- Type de variable conditionnelle : pthread_cond_t
- On peut dfinir une variable conditionnelle de manire statique avec des attributs par dfaut :
pthread_con_t NomCond = PTHREAD_COND_INITIALIZER;
- Une variable conditionnelle p
peut aussi tre initialise de manire dynamique
y q par
p
int pthread_cond_init(pthread_cond_t *cond,
const pthread_condattr_t *attr = NULL)
struct pthread_condattr_t { int __dummy; } pthread_condattr_t;
- Une variable conditionnelle est dtruite par
int pthread_cond_destroy (pthread_cond_t *cond)
- Un thread se bloque en attente quune variable conditionnelle devienne vraie
int p
pthread_cond_wait p
pthread_cond_t *cond,
, p
pthread_mutex_t *mutex)
)
- Un thread peut signaler une variable conditionnelle par
int pthread_cond_signal (pthread_cond_t *cond)
(si aucun thread est en attente de la variable, le signal est perdu contrairement V(sem))

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


68

- Un thread peut signaler une variable conditionnelle tous les threads en attente par
int pthread_cond_braodcast (pthread_cond_t *cond)

- Posix 1000.3 de 1999 dfinit aussi lattente temporise sur une condition pour viter le
blocage infini
int pthread_cond_timedwait(pthread_cond_t *cond,
pthread_mutex_t *mutex, const struct timespec *abstime)

z Autres primitives relatives aux variables conditionnelles


- pthread_cond_attr_init : initialise les attributs dune var-cond
- pthread_condattr_destroy : dtruit des attributs de variable conditionnelle
- pthread_condattr_getshared : test si une var-cond est partageable entre processus
- pthread_condattr_setshared : modifie lattribut de partage dune var-cond

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


69

14
Exemple 1 dapplication avec variable conditionnelle

z Dans lexemple suivant un thread incrmente un compteur, les autres attendent quil
franchisse le seuil de 100.

// Thread de calcul // Threads qui attendent le //


franchissement du seuil de 100
pthread_cond_t VarCond =
PTHREAD_COND_INITIALIZER ; pthread_mutex_init(&Verrou, NULL);
pthread_cond_init(&VarCond, NULL);

while (...) {
pthread_mutex_lock (&Verrou);

while (100 < Compteur)
pthread_mutex_lock(&Verrou);
pthread_cond_wait(&VarCond, &Verrou);
Compteur++;
printf ("Seuil atteint! "\n);
if (Compteur > 100)
pthread_mutex_unlock (&Verrou);
pthread_cond_broadcast (&VarCond);
pthread_mutex_unlock (&Verrou);

}

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


70

Exemple 2 dapplication avec variable conditionnelle

z Description de lexemple
- Un robot doit envoyer rgulirement des informations de temprature
- Il dispose pour cela dun capteur de temprature
- On dcide dattribuer une tche le travail de lecture p
priodique
q du capteur
p (toutes
(
les secondes) et de transmettre une autre tche la valeur moyenne sur 10 mesures
- La seconde tche fait un pr-traitement de cette moyenne et envoie son rythme ces
informations vers un central

- On modlise dans ce problme le capteur et les deux tches; linteraction du robot


et du superviseur central nest pas aborde.

Analyse de la
Capteur de
temprature moyenne
temprature

Valeur de Tampon
temprature dchange

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


71

15
z Solution avec mutex et variable conditionnelle

#include <stdio.h>
#include <pthread.h>
typedef unsigned char Registre_8_Bits;
Registre_8_Bits *capteurTemperature; // a mapper sur adresse registre
unsigned int periodeLecture = 1000*1000; // 1 seconde = 106 micro secondes
unsigned int nombreDonnees = 10; // 10 lectures avant de transmettre
pthread_mutex_t mutexTampon = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t attenteDonnee; // variable conditionnelle, pour la gestion du
// tampon dchange, initialise dans le
// programme principal avant de lancer les tches

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


72

z Solution avec mutex et variable conditionnelle

// le code associ la gestion du tampon : utilisation dune variable conditionnelle


Registre_8_Bits valeurTampon = 0;
int valeurPrete = 0;
void Tampon_metAJour(Registre_8_Bits v){
pthread_mutex_lock( &mutexTampon);
valeurTampon = v;
valeurPrete = 1;
pthread_cond_signal( &attenteDonnee);
pthread_mutex_unlock( &mutexTampon);
}

void Tampon_lectureQuandPret(Registre_8_Bits *v){


pthread_mutex_lock( &mutexTampon);
while ( !valeurPrete){
pthread cond wait( &attenteDonnee
pthread_cond_wait( &attenteDonnee, &mutexTampon);
}
*v = valeurTampon;
valeurPrete = 0;
pthread_mutex_unlock( &mutexTampon);
}

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


73

16
// le code associ la tche de lecture rgulire du registre
// (cest une version simplifie pour la gestion du temps)
void codeLectureReguliere(void){
int somme, CPT = 0;
while(1){
usleep(periodeLecture);
somme += *capteurTemperature;
CPT ++;
if (CPT == nombreDonnees){
somme /= nombreDonnees;
Tampon_metAJour(somme);
CPT = somme = 0;
}
}
}

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


74

// le code associ la tche de calcul (analyse de la temprature)


void codeCalcul(void){
Registre_8_Bits moyenneTemp;
Registre_8_Bits leMin = 255;
Registre 8 Bits leMax = 0;
Registre_8_Bits
while(1){
Tampon_lectureQuandPret(&moyenneTemp);
if (moyenneTemp < leMin)
leMin = moyenneTemp;
if (moyenneTemp > leMax)
leMax = moyenneTemp;
printf("Valeur temp = %d\n", moyenneTemp);
printf("min = %d, max = %d", leMin, leMax);
}
}

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


75

17
int main(){
pthread_t tacheCalcul;
pthread_t tacheLecture;

pthread cond init( &attenteDonnee


pthread_cond_init( &attenteDonnee, NULL);
capteurTemperature = (Registre_8_Bits *) malloc(1*sizeof(Registre_8_Bits));
pthread_create(&tacheLecture, NULL, (void *(*)()) codeLectureReguliere, NULL);
pthread_create(&tacheCalcul, NULL, (void *(*)()) codeCalcul, NULL);
pthread_join(tacheLecture, NULL); // ne doit jamais arriver
pthread_join(tacheCalcul, NULL); // ne doit jamais arriver
printf("Bizarre : terminaison inattendue des deux tches !!!! \n");
return -1;
}

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


76

Signaux de Posix

z Principes

- Les diffrentes occurrences dun mme signal restent pendantes


(le nombre de signaux reus est gal au nombre de signaux mis).
- La priorit lie au signal est respecte
respecte, avec celle du thread
thread, dans la gestion de la file
dattente des signaux : les threads prioritaires son rveills selon leur priorit
- Les nouveaux signaux (par rapport Unix) sont au nombre de RTSIG_MAX et sont
numrots de SIGRTMIN SIGRTMAX.
- Les dfinitions ncessaires lutilisation des signaux se trouvent dans le fichiers <signal.h>

z Remarques

1) Attention
Att ti lutilisation
l tili ti des
d signaux
i avec les
l threads
th d peutt conduire
d i des
d erreurs difficiles
diffi il
dtecter au moment de lcriture du code. Ceci est d au fait que les threads dun process
partagent les mmes infos sur les signaux.

2) Lutilisation des signaux doit tre conforme lutilisation traditionnelle des signaux sous UNIX,
En particulier pour la dfinition des actions vnementielles

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


77

18
z Liste des signaux POSIX
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
5) SIGTRAP 6) SIGABRT 7) SIGEMT 8) SIGFPE
9) SIGKILL 10) SIGBUS 11) SIGSEGV 12) SIGSYS
13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGUSR1
17) SIGUSR2 18) SIGCHLD 19) SIGPWR 20) SIGWINCH
21) SIGURG 22) SIGIO 23) SIGSTOP 24) SIGTSTP
25) SIGCONT 26) SIGTTIN 27) SIGTTOU 28) SIGVTALRM
29) SIGPROF 300) SIGXCPU 31) SIGXFSZ

33) SIGRTMIN 34) SIGRTMIN+1 35) SIGRTMIN+2 36) SIGRTMIN+3 37)


SIGRTMIN+4 38) SIGRTMIN+5 39) SIGRTMIN+6 40) SIGRTMIN+7 41)
SIGRTMIN+8 42) SIGRTMIN+9 43) SIGRTMIN+10 44) SIGRTMIN+11 45)
SIGRTMIN+12 46) SIGRTMIN+13 47) SIGRTMIN+14 48) SIGRTMIN+15 49)
SIGRTMAX-15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12 53)
SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57)
SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61)
SIGRTMAX-3 62)) SIGRTMAX-2 63)) SIGRTMAX-1 64)) SIGRTMAX

Signaux Non Posix : SIGEMT SIGIO SIGPWR IGWINCH

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


78

z Primitives des manipulation de signaux


- Lattente de signal se fait par de trois manires :
1) Attente simple dun signal

int pthread_sigwait (const sigset_t *set, int *sig)

2) Attente de signal accompagne dinformation


d information

int pthread_sigwaitinfo (const sigset_t *set, siginfo_t *info)

3) Attente de signal temporise :


int pthread_sigtimedwait (const sigset_t *set, siginfo_t *info,
const struct timespec *timeout)

- Masquage de signaux
int p
pthread_sigmask
g (int how,
, const sigset
g _t *newmask,
, sigset
g _t *oldmask)

- Emission de signal un thread explicitement dsign


int pthread_kill (pthread_t thread, int signumber)

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


79

19
Exemple avec signaux et smaphores

Dans lexemple du programme suivant, on utilise un smaphore pour rveiller 5 threads


dans une fonction de capture de signal (de timer).

On notera que le smaphore est initialis 0 (par sem_init) pour bloquer tout processus
qui excute un sem_wait.

Le programme principal arme un timer cyclique.


Chaque occurrence du signal du timer permet de dbloquer un processus (par sem_post).

Le programme se termine quand chaque thread a t dbloqu (rveill) 5 fois.

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


80

#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <time.h>
#include "errors.h"
semt semaphore;
semt_
/* Fonction de capture de signal
void signal_catcher (int sig)
{ if (semp_post(&semaphore)==-1) erno_abort ("post sempahore"); }

/* Fonction Start de thread; cette routine attend le smaphore.


void *sem_waiter(void *arg)
{ int number = (int)arg; int CPT;
/* Chaque thread attend 5 fois
for (CPT=1; CPT <=5; CPT++)
{ while (sem_wait(&semphore)==-1)
if (errno!= EINTR) errno_abort("wait on sempahore"); }
printf(" %d waking (%d)...\n ", number, CPT);
}
return NULL ;
}
Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse
81

20
int main (int argc, char *argv[])
{ int thread_CPT, status;
struct sigevent sig_event;
struct sigaction sig_action;
sigset_t sig_mask;
timer_t timer_id;
struct itimerspec timer val;
pthread_t sem_waiters[5];

#if !defined(_POSIX_SEMAPHORES) || !defined(_POSIX_TIMERS)


# if !defined(_POSIX_SEMAPHORES)
printf(Smaphores non supports FIN\n);
# endif
return -1
# if !defined(_POSIX_TIMERS)
printf(Timers non supports FIN\n);
# endif
#else
sem_init(&sempahore, 0, 0);

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


82

/* Cration de 5 threads pour attendre le smaphore


for(thread_CPT = 0; thread_CPT < 5; thread_CPT++)
{ status = pthread_create (
&sem_waiters[thread_CPT], NULL,
sem_waiter, (void*)thread_CPT);
if (status !=0)
err_abort(status, erreur de cration de thread);
}

/* Armer un timer, en utilisant le signal SIGRTMIN, qui doit se dclencher


/* toutes les 2 secondes
sig_event.sigev_value.sival_int = 0;
sig_event.sigev_signo = SIGRTMIN ;
g_event.sigev
sig g _notify
y = SIGEV_SIGNAL ;

if (timer_create(CLOCK_REALTIME, &sig_event, &timer_id)==-1)


errno_abort(Erreur de cration de timer);

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


83

21
sigemptyset (&sig_mask);
sigaddset (&sig_mask, SIGRTMIN);
sig_action.sa_handler = signal_catcher;
sig_action.sa_flags = 0;
if (sigaction(SIGRTMIN, &sig_action, NULL) == -1)
errno_abort(erreur dinitialisation daction de signal);
timer_val.it_interval.tv_sec = 2;
timer_val.it_interval.tv_nsec = 0;
timer_val.it_value.tv_sec = 2;
timer_val.it_value.tv_nsec = 0.
if (timer_settime(timer_id, 0, &timer_val, NULL) == -1)
errno_abort(Erreur darmement du timer);

/* Attente de la terminaison de tous les threads.


for (thread_CPT = 0; thread_CPT < 5; thread_CPT++)
{ status = pthread_join(sem_waiters[thread_CPT],
pthread join(sem waiters[thread CPT] NULL);
if (status != 0) err_abort(status, Erreur de JOIN de thread);
}
return 0;
#endif
}

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


84

Interface pour la gestion du temps


clockid-t : type pour manipuler lhorloge
timer_t : type pour manipuler les timers

z Primitives de lAPI de gestion du temps


- int clock_settime
clock settime (clockid_t
(clockid t clock id const struct timespec *tp) : initialise
clock_id,
lhorloge

- int clock_gettime (clockid_t clock_id, struct timespec *tp) : lit la valeur de lhorloge
- int clock_getres (clockid_t clock_id, struct timespec *res) : renvoie la rsolution de
lhorloge

- int timer_create (clockid_t clock_id, struct sigevent *evp, timer_t *timerid) :


cre un timer en ayant comme base lhorloge donne en argument

- int timer_delete timer t timerid ) : dtruit un timer


timer delete ( timer-t

- int timer_settime( timer_t timerid, int flags,


const struct itimerspec *value, struct itimerspec *ovalue ) :
arme un timer avec une valeur de temporisation

- int timer_gettime ( timer_t timerid, struct itimerspec *value ) : lit le temps restant
un timer avant dexpirer

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


85

22
z Primitives de lAPI (suite)
- int timer_getoverrun ( timer_t timerid ) : lit le temps de dpassement dun timer
- int nanosleep( const struct timespec *rqtp, struct timespec *rmtp ) :
suspension
p du thread appelant
pp pendant
p une dure spcifie
p par
p rqtp.
q p
rmtp est gnralement gal NULL.

- Posix 1003.b de 1999 dfinit la fonction suivante qui permet dobtenir lId dune horloge :
int clock_getcpuclockid (pid_t pid, clockid_t *clock_id);

z Utilisation de lAPI

- LLutilisation
utilisation des primitives relatives au temps ncessite le fichier entte <time.h>
<time h>

- La constante _POSIX_CLOCKRES_MIN, dfinie dans <time.h>, spcifie la rsolution


(granularit) de lhorloge temps rel. Sa valeur dpend de la cible (par dfaut cest 20 ms).

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


86

Interface pour la gestion de messages Posix

z Principes de la communication par messages


Dpt et retrait de messages partir dune file (avec ventuellement un ordre position- des
messages dans la file que lon spcifie dans les oprations mq_send et mq_receive).

z Primitives de lAPI

- mqd-t mq_open ( const char *name, int oflag, ... ) : cre une file de messages
et la lie un processus. oflag spcifie les droits sur la file (criture, lecture ou les deux).

- int mq_close ( mqd_t mqdes ) : ferme une file de messages


- int mq_setattr ( mqd_t mqdes, const struct mq_attr *mqstat,
struct mq-attr *omqstat ) : change les caractristiques dune file de
messages (taille maxi de messages, nombre maxi de messages)
- int mq_getattr ( mqd-t mqdes, struct mq-attr *mqstat ) : renvoie les attributs
dune file de messages
- int mq_unlink ( const char *name ) : supprime une file de messages

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


87

23
z Primitives de lAPI (suite)

- int mq_send ( mqd_t mqdes, const char *msg_ptr, size_t msg_len,


unsigned int msg_prio ) : rajoute un message dans une file
- int mq_receive ( mqd_t mqdes, const char *msg_ptr, size_t msg_len,
unsigned
g int msg prio ) : extrait
g_p a unu message
ag dune
d u file

- int mq_notify( mqd_t mqdes, const struct sigevent *notification ) : avertit un


thread de larrive dun message dans une file.

- Posix 1003.b de 1999 dfinit des primitives de messages temporises


* mq_timedsend : en cas de manque de place dans la file, une quantit de temps est spcifie
pour indiquer lattente maxi avant de dposer un message
* mq_timedreceive : permet de recevoir (au bout dun dlai fix) un message,
ssilil n
nyy a pas de message, retour lappelant
l appelant au bout du temps spcifi.

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


88

z Lien intressant pour la description des primitives Posix

http://www.opengroup.org/onlinepubs/007908799/xshix.html

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


89

24
Etude de cas

Soit un atelier de production compos dun convoyeur, un robot dalimentation de pices usiner, M
machines dusinage et un robot de retrait de pices usines. Lensemble est reli par un rseau de
communication (voir figure ci-dessous).

Rseau de communication industriel

Superviseur

Oprateur

Table Table Table

Convoyeur
Robot_retrait
Robot_alimentation

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


90

Le superviseur reoit ses ordres de son environnement reprsent ici par un oprateur. On suppose que le
convoyeur tourne en permanence et que sa vitesse est choisie de manire adquate pour que les robots et
machines puissent manipuler les pices sans problme.
Quand loprateur signale au superviseur larrive dune nouvelle pice usiner (on suppose que chaque
pice est accompagne dun code qui spcifie lopration dusinage lui appliquer), le superviseur
dtermine la machine qui va lusiner et envoie un ordre au robot dalimentation pour dposer la pice sur le
y
convoyeur et la machine dusinage
g concerne pour
p se prparer.
p p Le robot dalimentation effectue
lopration de placement sur le convoyeur au bout de 20 secondes au maximum, sil ny arrive pas il gnre
un signal danomalie vers le superviseur qui fait passer le systme dans un tat de dfaillance.
Lorsquune machine dusinage retire la pice quelle doit usiner, elle la dpose sur sa table et envoie un
signal de libration du convoyeur au superviseur. Si la machine na pas retir la pice au bout de 50
secondes, le systme passe dans un tat de dfaillance. Chaque machine dusinage possde sa propre table
dusinage sur laquelle elle dpose la pice durant lopration dusinage. Lorsquune machine dusinage
termine son travail, elle envoie un compte rendu au superviseur et attend de celui-ci un ordre pour dposer
la pice sur le convoyeur. Si une machine na pas fini son travail au bout de 10 minutes, le superviseur
avertit loprateur en dclarant la machine en panne, mais narrte pas le systme. Si une pice arrive et
quelle ncessite une opration
q p sur une machine djj dclare en panne,
p , le superviseur
p passe
p dans un tat
de dfaillance. Lorsquun compte rendu de fin dusinage est reu, le superviseur attend que le convoyeur
soit libre, ensuite il envoie un ordre la machine dusinage concerne pour dposer la pice sur le
convoyeur et un ordre au robot de retrait pour retirer la pice afin de lenvoyer au dpt. Quand la pice est
retire un compte rendu est renvoy au superviseur par le robot de retrait. Si le robot de retrait na pas fini
son travail au bout de 30 secondes, le superviseur fait passer le systme dans un tat de dfaillance.

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


91

25
Comme il ny a quun seul convoyeur, le superviseur doit assurer sa bonne utilisation : une seule pice la
fois sur le convoyeur.
On suppose que tous les quipements (robots et machines dusinage) sont munis de capteurs pour dtecter
larrive de pices et leur dpart du convoyeur et que les robots et machines peuvent manipuler les pices
alors que le convoyeur est en mouvement.

Question
Modliser et programmer le problme dcrit prcdemment laide de thread Posix.
Bien rflchir au(x) mcanisme(s) de synchronisation utiliser.

Cours Module ASTRE Z. MAMMERI IRIT - UPS - Toulouse


92

26