Gestion des Threads
Samia Bouzefrane & Ziad Kachouh
[email protected]
http://cedric.cnam.fr/~bouzefra
Plan
• La gestion des threads
• La communication par les segments de
mémoire partagés
2
Descripteur
Descripteurdes
desprocessus
processusUnix
Unix
Bloc de contrôle (utilisé par Linux) comporte :
-État du processus
-Priorité du processus
-Signaux en attente
-Signaux masqués
-Pointeur sur le processus suivant dans la liste des processus prêts
-Numéro du processus
-Numéro du groupe contenant le processus
-Pointeur sur le processus père
-Numéro de la session contenant le processus
-Identificateur de l’utilisateur réel
-Identificateur de l’utilisateur effectif
-Politique d’ordonnancement utilisé
-Temps processeur consommé en mode noyau et en mode utilisateur
-Date de création du processus
-etc.
3
Création
Créationd’un
d’unprocessus
processusUnix
Unix
Un processus Unix = { un espace d’adressage et une unité d’exécution unique }
Contexte d’un processus Unix :
- pid,
- répertoire de travail,
- descripteurs,
-propriétaires,
-implantation en mémoire,
-registres,
-priorité d’ordonnancement,
-masque des signaux,
-pile d’exécution
Cela rend coûteuse la création d’un processus
4
Création
Créationde
dethreads
threadsUnix
Unix
Thread Unix: - processus léger
- permet de multiplier l’implémentation d’activités caractérisées par
des contextes plus légers que ceux des processus Unix
Contexte d’exécution d’une thread Unix:
- registres,
- priorité d’ordonnancement,
-masque des signaux,
-pile d’exécution.
L’espace virtuel d’une thread :
- code exécuté par la thread,
- données définies dans la thread et
- une pile d’exécution propre à la thread.
5
Primitives
Primitivesde
demanipulation
manipulationde
dethreads
threadsUnix
Unix
Création et activation d’une thread :
int pthread_create(
pthread_t *idptr, /* ptr sur la zone où sera retournée l’identité de la thread */
pthread_attr_t attr,/* attributs de la thread: pthread_attr_default ou 0 */
void *(*fonc) (void *), /* pointeur sur la fonction exécutée par la thread */
void *arg /* pointeur sur le(s) argument(s) passé(s) à la thread */
);
Terminaison d’une thread :
void pthread_exit (
void *status /* ptr sur le résultat retourné par la thread */
);
Libération des ressources d’une thread :
int pthread_detach(
pthread_t *idptr /* pointeur sur l’identité de la thread */
);
Attente de la terminaison d’une thread :
int pthread_join(
pthread_t id, /* identité de la thread attendue */
void *status /* pointeur sur le code retour de la thread attendue */
);
6
Exemple1
Exemple1de
dethreads
threadsUnix
Unix
/* Trois_Th.c */
#include <pthread.h> printf("Main: thread numero
int compteur[3]; %d creee: id = %d\n",num,
/* fonction executee par chaque pth_id[num]);
thread */ }
void *fonc_thread(void *k) { usleep(10000); /* attente de
printf("Thread numero %d : 10 ms */
mon tid est %d\n",(int) k, printf("Affichage des
pthread_self()); compteurs\n");
for(;;) compteur[(int) k]++; for(i=0;i<20; i++) {
} printf("%d \t%d \t%d\n",
main() { compteur[0], compteur[1],
int i, num; pthread_t th_id[3]; compteur[2]);
/* creation des threads */ usleep(1000);
for(num=0;num<3;num++) /* attente de 1 ms entre 2
{pthread_create(pth_id+num, 0, affichages */
fonc_thread,(void *) num); }
exit(0); } 7
Exemple2
Exemple2de
dethreads
threadsUnix
Unix
#include <pthread.h> a=atoi(argv[1]); b=atoi(argv[2]);
#include <stdio.h> c=atoi(argv[3]); d=atoi(argv[4]);
#include <errno.h> donnees1.x=a; donnees1.y=b;
typedef struct { donnees2.x=c; donnees2.y=d;
int x, y; /* creation des threads */
} data; pthread_create(pth_id, 0, (void
/* fonction executee par chaque thread *(*)())mul, &donnees1);
*/ pthread_create(pth_id+1, 0, (void
void *mul(data *ptrdata) *(*)())mul, &donnees2);
{ /* Attente de la fin de la thread 1 */
pthread_exit((void *)((ptrdata->x) * pthread_join(pth_id[0], (void **)
(ptrdata->y))); &res1);
} /* Attente de la fin de la thread 2 */
void main(int argc, char *argv[]){ pthread_join(pth_id[1], (void **)
int i; &res2);
int a, b, c, d; /* Affichage du resultat a*b + c*d */
pthread_t pth_id[2]; printf("Resultat =%d\n", res1+res2);
data donnees1; /* Suppression des ressources des
threads */
data donnees2;
pthread_detach(&pth_id[0]);
int res1, res2;
pthread_detach(&pth_id[1]);
if(argc < 5) { perror("\007Nbre
d'arguments incorrect"); exit(1);} exit(0); 8
}
Thread (3)
compilation avec :
gcc thread_exo1.c -o exo1 -lpthread
9
Les segments de mémoire partagés : introduction
• IPC : Inter Proccess Communication – System V d’Unix
• Repris dans POSIX
• Communication entre processus sur la même machine
• Librairies C:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
10
Création de segments de mémoire partagés
• Pour créer un segment de mémoire, on attache à ce
segment un certain nombre d’informations.
id unique
ftock() shmget()
Mode de création Description
Création si l’objet n’existe pas déjà. Sinon
IPC_CREAT
aucune erreur
Création si l’objet n’existe pas déjà. Sinon
IPC_CREAT | IPC_EXECL
erreur
Création si l’objet demandé et association de
IPC_PRIVATE
celui-ci à l’identificateur fourni
Aucun mode précisé Erreur si l’objet n’existe pas
11
Partage de données
• Les segments de mémoire partagés permettent à deux
processus distincts de partager physiquement des données.
Processus A Processus B
Segments partagés
…
Données… Données…
Données…
12
Obtention d’un segment de mémoire
La primitive shmget()
int shmget( key_t cle, int taille, int options);
- cle est la clé obtenu par la fonction ftok()
- taille est le nombre d'octets du segment
- options indique les droits d'accès au segment, PC_CREAT | 0666
par exemple
13
Attachement d’un segment de mémoire
void *shmat(int shmid, const void *adr, int options);
- shmid est l'identificateur du segment
-adr est l'adresse virtuelle à laquelle doit être implanté le segment
dans l'espace adressable du processus; une valeur 0 permet de
laisser le choix de cette adresse au système.
-options peut valoir SHM_RDONLY pour s'attacher un segment en
lecture seule.
14
Détachement d’un segment de mémoire
La primitive shmdt() détache un segment de l'espace adressable
d'un processus.
int shmdt( const void *adr );
adr est l’adresse retournée par shmat.
Un segment non détaché sera détaché automatiquement lorsque
tous les processus qui se le sont attachés se terminent.
15
Suppression d’un segment de mémoire
int shmctl(int shmid, int option, struct shm_ds *p )
permet d'agir sur un segment partagé.
Si l’option est égale à :
- IPC_RMID : suppression du segment identifié par shmid (la
suppression sera effective lorsque aucun processus n'est plus attaché au
segment.
16
Exemple d’utilisation/1
// shm_prod.c
struct donnees { int nb; int total; };
void main(void) {
key_t cle; // dans stdlib.h
int id;
struct donnees *commun;
int reponse;
cle = ftok(getenv("HOME"), 'A');
id = shmget(cle, sizeof(struct donnees), IPC_CREAT | IPC_EXCL | 0666);
commun = (struct donnees *) shmat(id, NULL, SHM_R | SHM_W); // shm.h
commun->nb = 0;
commun->total = 0;
while (1) {
printf("+ ");
scanf("%d", &reponse);
commun->nb++;
commun->total += reponse;
printf("sous-total %d = %d\n", commun->nb, commun->total);
}
printf("---\n");
err = shmdt((char *) commun); /* détachement du segment */
err = shmctl(id, IPC_RMID, NULL); /* suppression segment */
}
17
Exemple d’utilisation/2
// shm_cons.c
#define DELAI 2
struct donnees { int nb; int total; };
void main(void)
{
key_t cle; // dans stdlib.h
int id;
struct donnees *commun;
cle = ftok(getenv("HOME"), 'A');
id = shmget(cle, sizeof(struct donnees), 0);
commun = (struct donnees *) shmat(id, NULL, SHM_R); // shm.h
while (1) {
sleep(DELAI);
printf("sous-total %d = %d\n", commun->nb, commun->total);
}
printf("---\n");
err = shmdt((char *) commun);
}
18
Exemple d’utilisation/3
$ ./shm_prod $ ./shm_cons
+ 10 sous-total 0 = 0
sous-total 1 = 10 sous-total 0 = 0
+ 20 sous-total 1 = 10
sous-total 2 = 30 sous-total 1 = 10
+ sous-total 2 = 30
sous-total 2 = 30
sous-total 2 = 30
---
Le producteur lancé, on saisit 10 pour
augmenter la valeur en mémoire $ ./shm_cons
sous-total 2 = 30
sous-total 2 = 30
sous-total 2 = 30
sous-total 2 = 30
---
Le consommateur lancé la première fois affiche les valeurs. Puis on quitte.
Le deuxième lancement du consommateur indique bien la dernière valeur en mémoire.
19