Documente Academic
Documente Profesional
Documente Cultură
Cet article fournit les bases de l'utilisation de la bibliothque pthread (POSIX threads) par une approche pragmatique. Votre avis et vos suggestions sur cet article nous intressent ! Alors aprs votre lecture, n'hsitez pas :
Utilisation de la bibliothque pthread par Emmanuel Delahaye (Espace personnel d'Emmanuel Delahaye)
I - Systmes multi-tches............................................................................................................................................ 3 I-A - Introduction.....................................................................................................................................................3 I-B - Processus.......................................................................................................................................................3 I-B-1 - Excution............................................................................................................................................... 3 I-B-2 - Cration dynamique de processus........................................................................................................4 I-C - Processus lgers........................................................................................................................................... 4 II - Introduction.............................................................................................................................................................5 II-A - Note pour Windows...................................................................................................................................... 5 II-B - Objectif.......................................................................................................................................................... 5 III - Hello worlds...........................................................................................................................................................6 IV - Donnes..............................................................................................................................................................10 IV-A - viter les globales '-la-barbare'............................................................................................................... 10 IV-B - Un seul code pour plusieurs tches..........................................................................................................11 IV-C - Le cas de l'crivain et du lecteur.............................................................................................................. 14 V - Synchronisation....................................................................................................................................................20 VI - Rsum des types et fonctions utiliss..............................................................................................................22 VII - Ressources........................................................................................................................................................ 23
-2Copyright 2008 - Emmanuel Delahaye. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://emmanuel-delahaye.developpez.com/tutoriels/c/
Utilisation de la bibliothque pthread par Emmanuel Delahaye (Espace personnel d'Emmanuel Delahaye)
I-B - Processus
Un processus est une application (ou un programme) en cours d'excution. Un programme, est avant tout un fichier stock sur un disque quelconque contenant du code excutable. Pour pouvoir tre excut, il faut runir un certain nombre de conditions : charger le programme en mmoire rserver de l'espace pour les donnes statiques rserver de l'espace dans la pile initialiser les pointeurs d'instructions et de pile lancer l'excution
A un processus est donc associ un espace mmoire compos d'un programme (code excutable) et de donnes (statiques et pile).
I-B-1 - Excution
Dans un systme multi-tches comme Unix ou Windows (mais pas MS-DOS), "lancer l'excution" signifie rendre le processus "ligible", c'est dire que ds que le processeur est libre, il pourra l'excuter rellement (il devient alors "lu"). Ds que le programme rencontre une fonction qui le fait 'attendre' (suspension temporise, attente d'une entre etc.) le systme (en fait, l'ordonnanceur, qui est le mcanisme de rpartition du temps machine) en profite pour suspendre l'excution du processus ("suspendu"). Le premier processus ligible passe alors en mode "lu". (il "prend la main" comme on dit vulgairement). Il faut savoir qu'il existe certaines tches dites 'immdiates' (interruptions) qui peuvent s'excuter en temps rel chaque instant. C'est notamment le cas pour les traitements de bas niveau de type timer (dterminer une chance) ou clavier, rseau, disque etc. Les vnements dtcts sont transmis au systme qui dtermine alors quel processus suspendu ils correspondent et si il s'agit bien d'un vnement de dblocage. ("en attente d'un <enter>", "en attente d'une trame rseau" etc). Si c'est le cas, le processus passe en tat "ligible". La suite, on la connait. En rsum, les tats d'un processus sont :
-3Copyright 2008 - Emmanuel Delahaye. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://emmanuel-delahaye.developpez.com/tutoriels/c/
Utilisation de la bibliothque pthread par Emmanuel Delahaye (Espace personnel d'Emmanuel Delahaye)
-4Copyright 2008 - Emmanuel Delahaye. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://emmanuel-delahaye.developpez.com/tutoriels/c/
Utilisation de la bibliothque pthread par Emmanuel Delahaye (Espace personnel d'Emmanuel Delahaye)
II - Introduction
La norme POSIX.1 fournit un ensemble de primitives permettant de raliser des processus lgers. Contrairement aux processus habituels, la mmoire est commune. Ces processus lgers sont communment appels 'threads' ou 'tches'. Selon l'implmentation, l'ensemble des primitives est, par exemple, regroup dans la bibliothque libpthread.a (gcc) qu'il faut bien sr penser ajouter au projet (-lpthread).
II-B - Objectif
Le but de cet article est de fournir les bases de l'utilisation de la bibliothque pthread par une approche pragmatique.
-5Copyright 2008 - Emmanuel Delahaye. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://emmanuel-delahaye.developpez.com/tutoriels/c/
Utilisation de la bibliothque pthread par Emmanuel Delahaye (Espace personnel d'Emmanuel Delahaye)
static void *task_b (void *p_data) { puts ("Hello world B"); (void) p_data; return NULL;
int main (void) { pthread_t ta; pthread_t tb; puts ("main init"); pthread_create (&ta, NULL, task_a, NULL); pthread_create (&tb, NULL, task_b, NULL); puts ("main end"); } return 0;
La sortie est, par exemple, celle-ci. Attention, l'ordre dans lequel l'excution des tches se fait n'est pas dfini (normal, puisque dans l'idal, elles sont concurrentes).
main init main end Hello world A Hello world B
Il est important de bien interprter les lignes produites. Dans cet exemple, il y a un processus (l'application) et 3 tches : main() task_a() task_b()
-6Copyright 2008 - Emmanuel Delahaye. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://emmanuel-delahaye.developpez.com/tutoriels/c/
Utilisation de la bibliothque pthread par Emmanuel Delahaye (Espace personnel d'Emmanuel Delahaye)
Il est clair, la vue des lignes produites, que la tche main() se termine avant que les autres ne soient lances. Cela signifie que, tant donn que le contexte des tches n'existe plus, le comportement des tches devient indtermin. C'est pourquoi il existe la fonction de synchronisation pthread_join() qui permet de suspendre l'excution de la tche courante en attendant la fin d'une tche dtermine.
#include <stdio.h> #include <pthread.h> static void *task_a (void *p_data) { puts ("Hello world A"); (void) p_data; return NULL;
static void *task_b (void *p_data) { puts ("Hello world B"); (void) p_data; return NULL;
int main (void) { pthread_t ta; pthread_t tb; puts ("main init"); pthread_create (&ta, NULL, task_a, NULL); pthread_create (&tb, NULL, task_b, NULL); #if 1 pthread_join (ta, NULL); pthread_join (tb, NULL); #endif puts ("main end"); } return 0;
Dans la ralit, une tche est gnralement une boucle (infinie ou non).
#include <stdio.h> #include <pthread.h> static void *task_a (void *p_data) { int i; for (i = 0; i < 5; i++) { printf ("Hello world A (%d)\n", i); } (void) p_data; -7Copyright 2008 - Emmanuel Delahaye. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://emmanuel-delahaye.developpez.com/tutoriels/c/
Utilisation de la bibliothque pthread par Emmanuel Delahaye (Espace personnel d'Emmanuel Delahaye) return NULL;
static void *task_b (void *p_data) { int i; for (i = 0; i < 7; i++) { printf ("Hello world B } (void) p_data; return NULL;
(%d)\n", i);
int main (void) { pthread_t ta; pthread_t tb; puts ("main init"); pthread_create (&ta, NULL, task_a, NULL); pthread_create (&tb, NULL, task_b, NULL); #if 1 pthread_join (ta, NULL); pthread_join (tb, NULL); #endif puts ("main end"); } return 0;
ou
main init Hello world Hello world Hello world Hello world Hello world Hello world Hello world Hello world Hello world Hello world Hello world Hello world main end A B B A A B B B A A B B (0) (0) (1) (1) (2) (2) (3) (4) (3) (4) (5) (6)
-8Copyright 2008 - Emmanuel Delahaye. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://emmanuel-delahaye.developpez.com/tutoriels/c/
Utilisation de la bibliothque pthread par Emmanuel Delahaye (Espace personnel d'Emmanuel Delahaye)
mais on constate que le mcanisme de rendez-vous fonctionne et que les deux boucles sont termines correctement. Sans le mcanisme de synchronisation :
#if 0 pthread_join (ta, NULL); pthread_join (tb, NULL); #endif
on aurait, par exemple, obtenu ceci, ce qui n'est pas loin d'une catastrophe...
main init main end Hello world Hello world Hello world Hello world Hello world Hello world Hello world Hello world Hello world Hello world
A A B B B A A B B A
-9Copyright 2008 - Emmanuel Delahaye. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://emmanuel-delahaye.developpez.com/tutoriels/c/
Utilisation de la bibliothque pthread par Emmanuel Delahaye (Espace personnel d'Emmanuel Delahaye)
IV - Donnes
L'application tant forme d'un seul processus, les donnes sont communes toutes les tches. Cela signifie qu'une donne est partageable directement entre les processus. Le terme 'donnes communes' recouvre comme il se doit : les donnes statiques les donnes alloues les donnes locales
} return NULL;
static void *task_b (void *p_data) { if (p_data != NULL) { /* recuperer le contexte applicatif */ char const *s = p_data; int i; for (i = 0; i < 7; i++) { printf ("'%s' (%d)\n", s, i); }
} return NULL;
int main (void) { pthread_t ta; pthread_t tb; puts ("main init"); /* La chaine etant definie const sur ma machine, je force en (char*). * Dans la tche, 's' est bien de type 'char const *' */ pthread_create (&ta, NULL, task_a, (char*)"Tache A"); pthread_create (&tb, NULL, task_b, (char*)"Tache B"); pthread_join (ta, NULL); pthread_join (tb, NULL); - 10 Copyright 2008 - Emmanuel Delahaye. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://emmanuel-delahaye.developpez.com/tutoriels/c/
Utilisation de la bibliothque pthread par Emmanuel Delahaye (Espace personnel d'Emmanuel Delahaye)
(0) (1)
(4)
int main (void) { pthread_t ta; pthread_t tb; puts ("main init"); pthread_create (&ta, NULL, task, NULL); pthread_create (&tb, NULL, task, NULL); pthread_join (ta, NULL); pthread_join (tb, NULL); puts ("main end"); } return 0;
Utilisation de la bibliothque pthread par Emmanuel Delahaye (Espace personnel d'Emmanuel Delahaye) Hello world Hello world Hello world Hello world Hello world Hello world Hello world Hello world Hello world main end (1) (2) (3) (4) (0) (1) (2) (3) (4)
Process returned 0 (0x0) execution time : 0.041 s Press any key to continue.
Evidemment, on ne sait plus diffrencier les traitements, et on ne sait pas qui fait quoi. Mais grace au paramtre 'donnes', on va pouvoir personnaliser le fonctionnement des tches : Identificateur ("A" ou "B") Nombre de tours de boucles etc.
Comme il y a plusieurs paramtres, on dfinit une structure, on cre une instance par tche avec les paramtres voulus et on passe l'adresse de la structure au moment de la cration de la tche. Ensuite la tche rcupre l'adresse en paramtre. Il suffit alors d'initialiser un pointeur du bon type avec l'adresse, et on a alors accs aux champs. Par exemple :
#include <stdio.h> #include <pthread.h> struct data { char const *id; int n; }; static void *task (void *p_data) { if (p_data != NULL) { struct data *p = p_data; int i; for (i = 0; i < p->n; i++) { printf ("Hello world %s (%d)\n", p->id, i); }
} }
return NULL;
int main (void) { pthread_t ta; pthread_t tb; struct data data_a = { "A", 5 }; struct data data_b = { "B", 7 }; puts ("main init"); pthread_create (&ta, NULL, task, &data_a); pthread_create (&tb, NULL, task, &data_b); pthread_join (ta, NULL); pthread_join (tb, NULL); - 12 Copyright 2008 - Emmanuel Delahaye. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://emmanuel-delahaye.developpez.com/tutoriels/c/
Utilisation de la bibliothque pthread par Emmanuel Delahaye (Espace personnel d'Emmanuel Delahaye)
Process returned 0 (0x0) execution time : 0.032 s Press any key to continue.
Les essais on t faits sous Windows Vista SP1, qui ne semble pas pratiquer le time slicing... Chaque boucle va donc jusqu'au bout... Pour un fonctionnement plus raliste, on peut introduire une suspension dans les traitements :
#include <stdio.h> #include <pthread.h> /* http://www.bien-programmer.fr/clib/psleep/ */ #include "psleep/inc/psleep.h" struct data { char const *id; int n; }; static void *task (void *p_data) { if (p_data != NULL) { struct data *p = p_data; int i; for (i = 0; i < p->n; i++) { printf ("Hello world %s (%d)\n", p->id, i); msleep(1); }
} }
return NULL;
int main (void) { pthread_t ta; pthread_t tb; struct data data_a = { "A", 5 }; struct data data_b = { "B", 7 };
- 13 Copyright 2008 - Emmanuel Delahaye. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://emmanuel-delahaye.developpez.com/tutoriels/c/
Utilisation de la bibliothque pthread par Emmanuel Delahaye (Espace personnel d'Emmanuel Delahaye) puts ("main init"); pthread_create (&ta, NULL, task, &data_a); pthread_create (&tb, NULL, task, &data_b); pthread_join (ta, NULL); pthread_join (tb, NULL); puts ("main end"); } return 0;
Process returned 0 (0x0) execution time : 0.026 s Press any key to continue.
msleep() n'est pas standard. C'est une macro que j'ai invente qui permet d'crire des suspensions standards sous Windows et unixoides. Les dtails sont ici.
};
static void *task_w (void *p) { if (p != NULL) { /* recuperer le contexte applicatif */ struct data *p_data = p; int i;
- 14 Copyright 2008 - Emmanuel Delahaye. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://emmanuel-delahaye.developpez.com/tutoriels/c/
Utilisation de la bibliothque pthread par Emmanuel Delahaye (Espace personnel d'Emmanuel Delahaye) for (i = 0; i < p_data->nb; i++) { int x = p_data->psh->data; x++; p_data->psh->data = x; } printf ("'%s' (%d) data <- %d\n", p_data->sid, i, p_data->psh->data);
} return NULL;
static void *task_r (void *p) { if (p != NULL) { /* recuperer le contexte applicatif */ struct data *p_data = p; int i; for (i = 0; i < p_data->nb; i++) { printf (" " "'%s' (%d) data == %d\n", p_data->sid, i, p_data->psh->data); }
} return NULL;
int main (void) { pthread_t ta; pthread_t tb; struct shared sh = { .data = 0, }; struct data da = { .nb = 5, .sid = "Writer", .psh = &sh, }; struct data db = { .nb = 7, .sid = "Reader", .psh = &sh, }; puts ("main init"); pthread_create (&ta, NULL, task_w, &da); pthread_create (&tb, NULL, task_r, &db); pthread_join (ta, NULL); pthread_join (tb, NULL); puts ("main end"); } return 0;
- 15 Copyright 2008 - Emmanuel Delahaye. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://emmanuel-delahaye.developpez.com/tutoriels/c/
Utilisation de la bibliothque pthread par Emmanuel Delahaye (Espace personnel d'Emmanuel Delahaye) 'Reader' (1) data == 2 'Reader' (2) data == 2 'Reader' (3) data == 4 'Reader' (4) data == 4 'Reader' (5) data == 5 'Reader' (6) data == 5
'Writer' (1) data <- 2 'Writer' (2) data <- 3 'Writer' (3) data <- 4 'Writer' (4) data <- 5
main end
o l'on constate que les valeurs lues sont parfois fausses par rapport aux valeurs relles. Pour se prmunir contre ce problme, on doit valuer quelle est la 'zone critique', et ensuite la protger avec un 'smaphore'. C'est tout simplement un mcanisme qui va empcher une autre tche d'interrompre la section critique. Dans l'environnement pthread, ce mcanisme est appel mutex. Il met en oeuvre le type opaque pthread_mutex_t et les fonctions pthread_mutex_lock() et pthread_mutex_unlock(). Voici un exemple de protection de la section critique de l'crivain (empcher le lecteur d'accder en lecture pendant l'criture).
#include <stdio.h> #include <pthread.h> struct shared { int data; pthread_mutex_t mut; }; struct data { /* paramtres */ int nb; char const *sid; /* contexte partage' */ struct shared *psh;
};
static void *task_w (void *p) { if (p != NULL) { struct data *p_data = p; int i; for (i = 0; i < p_data->nb; i++) { /* debut de la zone critique */ pthread_mutex_lock (&p_data->psh->mut); { int x = p_data->psh->data; x++; p_data->psh->data = x; } printf ("'%s' (%d) data <- %d\n", p_data->sid, i, p_data->psh->data); pthread_mutex_unlock (&p_data->psh->mut); /* fin de la zone critique */ } } return NULL;
- 16 Copyright 2008 - Emmanuel Delahaye. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://emmanuel-delahaye.developpez.com/tutoriels/c/
Utilisation de la bibliothque pthread par Emmanuel Delahaye (Espace personnel d'Emmanuel Delahaye)
static void *task_r (void *p) { if (p != NULL) { struct data *p_data = p; int i; for (i = 0; i < p_data->nb; i++) { printf (" " "'%s' (%d) data == %d\n", p_data->sid, i, p_data->psh->data); }
} return NULL;
int main (void) { pthread_t ta; pthread_t tb; struct shared sh = { .data = 0, .mut = PTHREAD_MUTEX_INITIALIZER, }; struct data da = { .nb = 5, .sid = "Writer", .psh = &sh, }; struct data db = { .nb = 7, .sid = "Reader", .psh = &sh, }; puts ("main init"); pthread_create (&ta, NULL, task_w, &da); pthread_create (&tb, NULL, task_r, &db); pthread_join (ta, NULL); pthread_join (tb, NULL); puts ("main end"); } return 0;
'Reader' (0) data == 3 'Reader' (1) data == 4 'Reader' 'Reader' 'Reader' 'Reader' 'Reader' (2) (3) (4) (5) (6) data data data data data == == == == == 4 5 5 5 5
main end
- 17 Copyright 2008 - Emmanuel Delahaye. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://emmanuel-delahaye.developpez.com/tutoriels/c/
Utilisation de la bibliothque pthread par Emmanuel Delahaye (Espace personnel d'Emmanuel Delahaye)
Il faut aussi protger la lecture, c'est dire empcher l'crivain d'crire pendant la lecture :
#include <stdio.h> #include <pthread.h> struct shared { int data; pthread_mutex_t mut; }; struct data { /* paramtres */ int nb; char const *sid; /* contexte partage' */ struct shared *psh;
};
static void *task_w (void *p) { if (p != NULL) { struct data *p_data = p; int i; for (i = 0; i < p_data->nb; i++) { /* debut de la zone critique */ pthread_mutex_lock (&p_data->psh->mut); { int x = p_data->psh->data; x++; p_data->psh->data = x; } printf ("'%s' (%d) data <- %d\n", p_data->sid, i, p_data->psh->data); pthread_mutex_unlock (&p_data->psh->mut); /* fin de la zone critique */ } } return NULL;
static void *task_r (void *p) { if (p != NULL) { struct data *p_data = p; int i; for (i = 0; i < p_data->nb; i++) { /* debut de la zone critique */ pthread_mutex_lock (&p_data->psh->mut); printf (" " "'%s' (%d) data == %d\n", p_data->sid, i, p_data->psh->data); pthread_mutex_unlock (&p_data->psh->mut); /* fin de la zone critique */ } } return NULL; } int main (void) { pthread_t ta; - 18 Copyright 2008 - Emmanuel Delahaye. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://emmanuel-delahaye.developpez.com/tutoriels/c/
Utilisation de la bibliothque pthread par Emmanuel Delahaye (Espace personnel d'Emmanuel Delahaye) pthread_t tb; struct shared sh = { .data = 0, .mut = PTHREAD_MUTEX_INITIALIZER, }; struct data da = { .nb = 5, .sid = "Writer", .psh = &sh, }; struct data db = { .nb = 7, .sid = "Reader", .psh = &sh, }; puts ("main init"); pthread_create (&ta, NULL, task_w, &da); pthread_create (&tb, NULL, task_r, &db); pthread_join (ta, NULL); pthread_join (tb, NULL); puts ("main end"); } return 0;
'Reader' (0) data == 1 'Reader' (1) data == 2 'Reader' (2) data == 3 'Reader' (3) data == 4 'Reader' (4) data == 5 'Reader' (5) data == 5 'Reader' (6) data == 5
main end
- 19 Copyright 2008 - Emmanuel Delahaye. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://emmanuel-delahaye.developpez.com/tutoriels/c/
Utilisation de la bibliothque pthread par Emmanuel Delahaye (Espace personnel d'Emmanuel Delahaye)
V - Synchronisation
Nous avons pu constater qu'en environnement multi-tches, l'ordre d'excution des instructions de 2 tches diffrentes tait indtermin. C'est pourquoi il existe un mcanisme permettant la synchronisation. Par exemple, bloquer la tche courante en attente d'un vnement ou la dbloquer ds le dclenchement de cet vnement. Dans l'environnement pthread, on parle de 'condition'. L'objet est pthread_cond_t, les fonctions sont pthread_cond_wait() et pthread_cond_signal(). Dans l'exemple initial, les deux tches s'excutaient de faon dsordonne. Voici un mcanisme de synchronisation de la tche B par la tche A. Il a fallu ajouter une suspension dans la tche A afin de laisser du temps B de s'excuter.
#include <stdio.h> #include <pthread.h> /* http://www.bien-programmer.fr/clib/psleep/ */ #include "psleep/inc/psleep.h" struct shared { pthread_mutex_t mut; pthread_cond_t synchro; }; struct data { /* paramtres */ int nb; char const *sid; /* contexte partage' */ struct shared *psh;
};
static void *task_a (void *p) { if (p != NULL) { struct data *p_data = p; struct shared *psh = p_data->psh; int i; for (i = 0; i < p_data->nb; i++) { pthread_mutex_lock (&psh->mut); printf ("'%s' (%d)\n", p_data->sid, i); pthread_cond_signal (&psh->synchro); pthread_mutex_unlock (&psh->mut); msleep (1000); }
} return NULL;
static void *task_b (void *p) { if (p != NULL) { struct data *p_data = p; struct shared *psh = p_data->psh; int i; for (i = 0; i < p_data->nb; i++) { pthread_mutex_lock (&psh->mut); pthread_cond_wait (&psh->synchro, &psh->mut); - 20 Copyright 2008 - Emmanuel Delahaye. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://emmanuel-delahaye.developpez.com/tutoriels/c/
Utilisation de la bibliothque pthread par Emmanuel Delahaye (Espace personnel d'Emmanuel Delahaye) printf (" " "'%s' (%d)\n", p_data->sid, i); pthread_mutex_unlock (&psh->mut);
} } return NULL;
int main (void) { pthread_t ta; pthread_t tb; struct shared sh = { .mut = PTHREAD_MUTEX_INITIALIZER, .synchro = PTHREAD_COND_INITIALIZER, }; struct data da = { .nb = 5, .sid = "task A", .psh = &sh, }; struct data db = { .nb = 4, .sid = "Task B", .psh = &sh, }; puts ("main init"); pthread_create (&ta, NULL, task_a, &da); pthread_create (&tb, NULL, task_b, &db); pthread_join (ta, NULL); pthread_join (tb, NULL); puts ("main end"); } return 0;
- 21 Copyright 2008 - Emmanuel Delahaye. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://emmanuel-delahaye.developpez.com/tutoriels/c/
Utilisation de la bibliothque pthread par Emmanuel Delahaye (Espace personnel d'Emmanuel Delahaye)
Contexte de tche pthread_create() Cration d'une tche pthread_join() Attente de fin de tche pthread_mutex_t Smaphore d'exclusion mutuelle pthread_mutex_lock() Dbut de zone critique pthread_mutex_unlock() zone Fin de critique pthread_cond_t Condition pthread_cond_wait() Mise en attente pthread_cond_signal() Dclenchement Les essais ont t faits sous Windows 98 avec Dev-C++ et sa bibliothque pthread. L'ordonnanceur de Windows tant premptif, les aberrations de fonctionnement sont claires et videntes. Les essais raliss sous Linux embarqu (Kernel 2.4 pour Power PC) sont moins parlants, car sur ma configuration de test, l'ordonnanceur n'est pas premptif. Il semble aussi que, sous Windows XP, l'ordonnanceur ne soit pas premptif (time slicing), mais coopratif... A moins que j'interprte mal le fonctionnement... Remarques bienvenues. Les remarques reues font tat des faits suivants : L'ordonnanceur de GNU/Linux 2.4 est soit coopratif, soit premptif selon une option de compilation du noyau L'ordonnanceur de GNU/Linux 2.6 est premptif L'ordonnanceur de MS/Windows 98 est coopratif (blocage possible par une 'boucle blanche') L'ordonnanceur de MS/Windows NT/XP est premptif (vnements + time slicing)
- 22 Copyright 2008 - Emmanuel Delahaye. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://emmanuel-delahaye.developpez.com/tutoriels/c/
Utilisation de la bibliothque pthread par Emmanuel Delahaye (Espace personnel d'Emmanuel Delahaye)
VII - Ressources
Pour approfondir, je recommande cet excellent site POSIX Threads Programming.
- 23 Copyright 2008 - Emmanuel Delahaye. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de dommages et intrts.
http://emmanuel-delahaye.developpez.com/tutoriels/c/