Télécharger la présentation
La présentation est en train de télécharger. S'il vous plaît, attendez
Publié parMaximilien Soulier Modifié depuis plus de 10 années
1
jc/md/lp-01/06Synchronisation1
2
jc/md/lp-01/06Synchronisation2 Objectif du chapitre Création dune application ayant plusieurs threads Synchronisations entre threads –Section critique –Mutex –Événement –Sémaphore Exemples pratiques
3
jc/md/lp-01/06Synchronisation3 Nous avons vu comment créer un thread dans un processus dans le chapitre précédent. Nous poursuivons maintenant avec plusieurs threads dans un même processus. Dans un premier exemple, NOSYNC, nous allons faire apparaître une difficulté lorsque plusieurs threads sexécutent simultanément. Dans les exemples suivants, nous travaillerons sur plusieurs solutions au problème.
4
jc/md/lp-01/06Synchronisation4 Création de 2 Threads Créer un projet NOSYNC Un process va créer 2 threads fils A et B Ces threads font juste limpression de messages –Début de thread –Texte –Fin de thread La demande dimpression dun texte fait que le thread perd la main
5
jc/md/lp-01/06Synchronisation5 NOSYNC main (1) #include "stdafx.h" DWORD WINAPI THREAD_A(LPVOID p); DWORD WINAPI THREAD_B(LPVOID p); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { HANDLE H1,H2;
6
jc/md/lp-01/06Synchronisation6 NOSYNC main (2) printf("debut du main NOSYNC\n"); H1=CreateThread(0, 0, THREAD_A, 0, 0, 0); H2=CreateThread(0, 0, THREAD_B, 0, 0, 0); Sleep(5000); CloseHandle(H1); CloseHandle(H2); printf("fin du main NOSYNC\n"); getchar(); return 0; }
7
jc/md/lp-01/06Synchronisation7 NOSYNC Thread_A DWORD WINAPI THREAD_A(LPVOID p) { printf("debut du thread A\n"); printf("le loup et "); printf("\nl'agneau "); printf("fin du thread A\n"); return 0; }
8
jc/md/lp-01/06Synchronisation8 NOSYNC Thread_B DWORD WINAPI THREAD_B(LPVOID p) { printf("debut du thread B\n"); printf("la cerise"); printf("sur le gateau\n"); printf("fin du thread B\n"); return 0; }
9
jc/md/lp-01/06Synchronisation9 Résultat de lexécution
10
jc/md/lp-01/06Synchronisation10 Synchronisation Les messages sont mélangés Il faut « synchroniser » lexécution des threads, cest-à- dire, dans notre exemple, attendre quun message soit terminé avant dimprimer lautre Synchronisation possible par –Section critique –Mutex –Événement (Event) –Sémaphore
11
jc/md/lp-01/06Synchronisation11 Section critique : types Les types « section critique » et « pointeur sur section critique » sont définis par des typedef CRITICAL_SECTION cs; LPCRITICAL_SECTION lpcs; Cela permet des contrôles par le compilateur et contribue à éviter un usage inapproprié
12
jc/md/lp-01/06Synchronisation12 Section critique : fonctions (1) Initialisation dune section critique void InitializeCriticalSection( LPCRITICAL_SECTION lpCriticalSection ); Entrée en section critique void EnterCriticalSection( LPCRITICAL_SECTION lpCriticalSection ); Sortie dune section critique void LeaveCriticalSection( LPCRITICAL_SECTION lpCriticalSection );
13
jc/md/lp-01/06Synchronisation13 Section critique : fonctions (2) Restitution des ressources void DeleteCriticalSection( LPCRITICAL_SECTION lpCriticalSection ); Variante dentrée non bloquante BOOL TryEnterCriticalSection( LPCRITICAL_SECTION lpCriticalSection );
14
jc/md/lp-01/06Synchronisation14 Section critique : application Créer une application CRITIC qui imprime correctement les deux messages Déclaration dans main ou en variable globale dune variable section critique Utilisation de cette variable dans thread_A et thread_B pour contrôler limpression des messages
15
jc/md/lp-01/06Synchronisation15 CRITIC main (1) #include "stdafx.h" DWORD WINAPI THREAD_A(LPVOID p); DWORD WINAPI THREAD_B(LPVOID p); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { CRITICAL_SECTION cs; HANDLE H1,H2;
16
jc/md/lp-01/06Synchronisation16 CRITIC main (2) InitializeCriticalSection(&cs); printf("debut du main CRITIC\n"); H1=CreateThread( 0, 0, THREAD_A, &cs, 0, 0); H2=CreateThread( 0, 0, THREAD_B, &cs, 0, 0); Sleep(5000); CloseHandle(H1); CloseHandle(H2); DeleteCriticalSection(&cs); printf("fin du main CRITIC\n"); getchar(); return 0; }
17
jc/md/lp-01/06Synchronisation17 CRITIC thread_A DWORD WINAPI THREAD_A(LPVOID pCriticSec) { printf("debut du thread A\n"); EnterCriticalSection( (LPCRITICAL_SECTION)pCriticSec); printf("THREAD_A: le loup et "); printf("l'agneau\n"); LeaveCriticalSection( (LPCRITICAL_SECTION)pCriticSec); printf("fin du thread A\n"); return 0; }
18
jc/md/lp-01/06Synchronisation18 CRITIC thread_B DWORD WINAPI THREAD_B(LPVOID pCriticSec) { printf("debut du thread B\n"); EnterCriticalSection((LPCRITICAL_SECTION)p CriticSec); printf("THREAD_B: la cerise "); printf("sur le gateau\n"); LeaveCriticalSection((LPCRITICAL_SECTION)p CriticSec); printf("fin du thread B\n"); return 0; }
19
jc/md/lp-01/06Synchronisation19 Résultat de lexécution
20
jc/md/lp-01/06Synchronisation20 Mutex Mutex : raccourci pour mutual exclusion Objet système destiné à gérer les synchronisations par exclusion mutuelle Synchronisation –Intra-processus –Inter-processus Alloué au plus à un thread à un instant donné
21
jc/md/lp-01/06Synchronisation21 Mutex : fonctions (1) Création dun Mutex HANDLE CreateMutex( LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCTSTR lpName ); lpMutexAttributes : NULL pour CE bInitialOwner : prise ou non du mutex lpName : pointeur sur un nom ou NULL valeur retournée : création ou non du mutex, etc.
22
jc/md/lp-01/06Synchronisation22 MUTEX : fonctions (2) Attente de disponibilité du mutex DWORD WaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds); hHandle : handle du mutex dwMilliseconds : INFINITE (pas de time-out) valeur de retour : état du mutex Libération du mutex BOOL ReleaseMutex(HANDLE hMutex ); valeur de retour : réussite ou non
23
jc/md/lp-01/06Synchronisation23 MUTEX : fonctions (2) Attente de disponibilité du mutex DWORD WaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds); hHandle : handle du mutex dwMilliseconds : INFINITE (pas de time-out) valeur de retour : état du mutex Libération du mutex BOOL ReleaseMutex(HANDLE hMutex ); valeur de retour : réussite ou non
24
jc/md/lp-01/06Synchronisation24 Application MUTEX Créer une application MUTEX Utiliser les mutexes pour que les textes ne soient plus mélangés lors de limpression
25
jc/md/lp-01/06Synchronisation25 MUTEX main (1) #include "stdafx.h" DWORD WINAPI THREAD_A(HANDLE hMutex); DWORD WINAPI THREAD_B(HANDLE hMutex); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { HANDLE hMutex,H1,H2; printf("debut du main MUTEX\n"); hMutex=CreateMutex(NULL,FALSE,NULL );
26
jc/md/lp-01/06Synchronisation26 MUTEX main (2) H1=CreateThread(0,0,THREAD_A,hMutex,0,0); H2=CreateThread(0,0,THREAD_B,(LPVOID)hMutex,0,0); Sleep(5000); CloseHandle(H1); CloseHandle(H2); CloseHandle(hMutex); printf("fin du main MUTEX\n"); getchar(); return 0; }
27
jc/md/lp-01/06Synchronisation27 MUTEX thread_A DWORD WINAPI THREAD_A(HANDLE hMut) { printf("debut du thread A\n"); WaitForSingleObject(hMut,INFINITE); printf("THREAD_A: le loup et "); printf("l'agneau\n"); ReleaseMutex(hMut); printf("fin du thread A\n"); return 0; }
28
jc/md/lp-01/06Synchronisation28 MUTEX Thread_B DWORD WINAPI THREAD_B(HANDLE hMut) { printf("debut du thread B\n"); WaitForSingleObject(hMut,INFINITE); printf("THREAD_B: la cerise "); printf("sur le gateau\n"); ReleaseMutex(hMut); printf("fin du thread B\n"); return 0; }
29
jc/md/lp-01/06Synchronisation29 Résultat de lexécution
30
jc/md/lp-01/06Synchronisation30 Synchronisation par événement Autre forme de synchronisation plus souple que par les mutex Gestion plus riche des événements –Création –Prise de possession –Restitution –Transmission de données –Ouvertures multiples
31
jc/md/lp-01/06Synchronisation31 Événements : fonctions (1) Création dun événement HANDLE CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPTSTR lpName ); lpEventAttributes: NULL pour CE bManualReset: TRUE autorise ResetEvent bInitialState: TRUE événement disponible lpName: NULL pour un événement sans nom
32
jc/md/lp-01/06Synchronisation32 Événements : fonctions (2) Ouverture dévénement HANDLE OpenEvent( DWORD dwDesiredAcess, BOOL bInheritHandle, LPCTSTR lpName); Fournit un handle sur un événement déjà créé par CreateEvent Correspondance par le nom lpName
33
jc/md/lp-01/06Synchronisation33 Événements : fonctions (3) Attente dévénement DWORD WaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds); Activation de lévénement BOOL SetEvent(HANDLE hEvent); Désactivation de lévénement BOOL ResetEvent(HANDLE hEvent);
34
jc/md/lp-01/06Synchronisation34 Événements : fonctions (4) Dépôt dune donnée BOOL SetEventData(HANDLE hEvent, DWORD dwData); hEvent : handle de lévénement dwData : donnée à affecter Récupération de la donnée déposée DWORD GetEventData(HANDLE hEvent); valeur de retour : la donnée déposée
35
jc/md/lp-01/06Synchronisation35 Application EVENT Créer une application EVENT EventA est créé actif dans le thread A pour autoriser la tâche A à démarrer EventB est créé inactif dans le thread B La tâche A désactivera EventA en début de tâche et activera EventB en fin de tâche La tâche B désactivera EventB en début de tâche et réactivera EventA en fin de tâche Les 2 tâches vont sactiver mutuellement
36
jc/md/lp-01/06Synchronisation36 EVENT main (1) #include "stdafx.h" DWORD WINAPI THREAD_A(LPVOID p); DWORD WINAPI THREAD_B(LPVOID p); HANDLE hEventA,hEventB; //variables globales pour… int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { HANDLE H1,H2; printf("debut du main EVENT\n");
37
jc/md/lp-01/06Synchronisation37 EVENT main (2) hEventA=CreateEvent(NULL,TRUE,TRUE,NULL); hEventB=CreateEvent(NULL,TRUE,FALSE,NULL); H1=CreateThread(0,0,THREAD_A,0,0,0); H2=CreateThread(0,0,THREAD_B,0,0,0); Sleep(5000); CloseHandle(H1); CloseHandle(H2); CloseHandle(hEventA); CloseHandle(hEventB); printf("fin du main EVENT\n"); getchar(); return 0; }
38
jc/md/lp-01/06Synchronisation38 EVENT THREAD_A DWORD WINAPI THREAD_A(LPVOID p) { printf("debut du thread A\n"); WaitForSingleObject(hEventA,INFINITE); printf("THREAD_A: le loup et "); printf("l'agneau\n"); ResetEvent(hEventA); SetEvent(hEventB); printf("fin thread A\n"); return 0; }
39
jc/md/lp-01/06Synchronisation39 EVENT THREAD_B DWORD WINAPI THREAD_B(LPVOID p) { printf("debut thread B\n"); WaitForSingleObject(hEventB,INFINITE); printf("THREAD_B: la cerise "); printf("sur le gateau\n"); ResetEvent(hEventB); SetEvent(hEventA); printf("fin thread B\n"); return 0; }
40
jc/md/lp-01/06Synchronisation40 Résultat de lexécution
41
jc/md/lp-01/06Synchronisation41 Application EVENT_NOM Lapplication est du même style que EVENT, mais montre lusage dautres fonctionnalités : –Événements nommés –Passage de donnée –Utilisation dun dépassement de délai Le thread imprime un message ou un autre suivant la donnée fournie, 1 ou 2
42
jc/md/lp-01/06Synchronisation42 EVENT_NOM : main (1) // EVENT_NOM.cpp : Defines the entry point for the… #include "stdafx.h" #include "Pkfuncs.h"//pour les fonctions SetEventData… DWORD WINAPI THREAD_A(LPVOID p); DWORD WINAPI THREAD_B(LPVOID p); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
43
jc/md/lp-01/06Synchronisation43 EVENT_NOM : main (2) { HANDLE H1,H2; HANDLE hEventA,hEventB; LPTSTR pNomEventA={L"NOM_EVENT_A"}; LPTSTR pNomEventB={L"NOM_EVENT_B"}; printf("debut du main EVENT_NOM\n"); hEventA=CreateEvent( NULL,TRUE,TRUE,pNomEventA); SetEventData(hEventA,1); hEventB=CreateEvent( NULL,TRUE,FALSE,pNomEventB); H1=CreateThread(0,0,THREAD_A,0,0,0); H2=CreateThread(0,0,THREAD_B,0,0,0);
44
jc/md/lp-01/06Synchronisation44 EVENT_NOM : main (3) Sleep(5000); CloseHandle(H1); CloseHandle(H2); CloseHandle(hEventA); CloseHandle(hEventB); printf("fin du main EVENT_NOM\n"); getchar(); return 0; }
45
jc/md/lp-01/06Synchronisation45 EVENT_NOM : THREAD_A (1) DWORD WINAPI THREAD_A(LPVOID p) { DWORD dwData_A; DWORD dwTime_out=1000; HANDLE hEvent_A,hEvent_B; LPTSTR pNomEventA={L"NOM_EVENT_A"}; LPTSTR pNomEventB={L"NOM_EVENT_B"}; printf("debut du thread A\n"); hEvent_A=OpenEvent(EVENT_ALL_ACCESS, FALSE,pNomEventA); hEvent_B=OpenEvent(EVENT_ALL_ACCESS, FALSE,pNomEventB);
46
jc/md/lp-01/06Synchronisation46 EVENT_NOM : THREAD_A (2) while(WAIT_OBJECT_0==WaitForSingleObject(hEvent_A,dwTime_out)) { dwData_A=GetEventData(hEvent_A); printf("THREAD_A: fable %d : ",dwData_A); switch (dwData_A) { case 1 : printf("le loup "); printf("et l'agneau\n"); break; case 2 : printf("le lion et "); printf("le rat\n"); break; default : break; }
47
jc/md/lp-01/06Synchronisation47 EVENT_NOM : THREAD_A (3) ResetEvent(hEvent_A); SetEvent(hEvent_B); } printf("fin thread A\n"); return 0;
48
jc/md/lp-01/06Synchronisation48 EVENT_NOM : THREAD_B (1) DWORD WINAPI THREAD_B(LPVOID p) { HANDLE hEvent_A,hEvent_B; LPTSTR pNomEventA={L"NOM_EVENT_A"}; LPTSTR pNomEventB={L"NOM_EVENT_B"}; printf("debut thread B\n"); hEvent_A=OpenEvent(EVENT_ALL_ACCESS,FALSE,p NomEventA); SetEventData(hEvent_A,2); hEvent_B=OpenEvent(EVENT_ALL_ACCESS,FALSE,p NomEventB); WaitForSingleObject(hEvent_B,INFINITE);
49
jc/md/lp-01/06Synchronisation49 EVENT_NOM : THREAD_B (2) printf("THREAD_B: la cerise "); printf("sur le gateau\n"); ResetEvent(hEvent_B); SetEvent(hEvent_A); Sleep(2000); //suivant valeur : fin de A avant B ou de B avant A printf("fin thread B\n"); return 0; }
50
jc/md/lp-01/06Synchronisation50 Résultat de lexécution
51
jc/md/lp-01/06Synchronisation51 Sémaphore (1) Contrôle le nombre des accès à une ressource par la distribution de jetons Valeur maximale fixée à la création Chaque utilisateur prend et restitue un ou plusieurs jetons sur le sémaphore Fonctionne entre processus indépendants Exclusion mutuelle dans le seul cas dun jeton à valeur maximum de 1
52
jc/md/lp-01/06Synchronisation52 Sémaphore (2) Le nombre de jetons disponibles est égal à tout instant au nombre des utilisateurs de la ressource gérée par le sémaphore Chaque fois quun un jeton est pris, le compteur de jeton est décrémenté Chaque fois quun jeton est restitué, le compteur de jeton est incrémenté Lorsque le nombre de jetons disponibles est 0, la ressource nest plus disponible
53
jc/md/lp-01/06Synchronisation53 Sémaphores : fonctions (1) Création dun sémaphore sans nom ou nommé CreateSemaphore Prise de jeton WaitForSingleObject Restitution de jeton ReleaseSemaphore Fermeture : CloseHandle déjà rencontrée Ouverture dun sémaphore nommé : la fonction nest pas implémentée mais CreateSemaphore peut la remplacer
54
jc/md/lp-01/06Synchronisation54 Sémaphores : fonctions (2) HANDLE CreateSemaphore( LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCTSTR lpName ); Arguments –pSemaphoreAttributes: inutilisé, NULL pour Windows CE –lInitialCount: jetons mis en jeu à la création –lMaximumCount: valeur maximale du compteur de jetons –lpName: NULL pour un sémaphore sans nom ou pointeur sur un nom pour un sémaphore nommé Valeur de retour : NULL si échec ou handle
55
jc/md/lp-01/06Synchronisation55 Sémaphores : fonctions (3) WaitForSingleObject : déjà rencontrée BOOL ReleaseSemaphore( HANDLE hSemaphore, LONG lReleaseCount, LPLONG); –Arguments hSemaphore: handle fourni à la création lReleaseCount: nombre des jetons à restituer lpPreviousCount: pointeur sur une variable qui sera garnie par le compteur de jeton avant la mise à jour –Valeur de retour : réussite ou non
56
jc/md/lp-01/06Synchronisation56 Application SEMA Créer une application SEMA Ressource contrôlée : impression dun message Utiliser un sémaphore à valeur maximum de 2 pour simuler une ressource quon ne peut attribuer que deux fois
57
jc/md/lp-01/06Synchronisation57 SEMA main (1) #include "stdafx.h" DWORD WINAPI THREAD_A(LPVOID p); DWORD WINAPI THREAD_B(LPVOID p); HANDLE hSem; int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { HANDLE H1,H2; printf("debut du main SEMA\n");
58
jc/md/lp-01/06Synchronisation58 SEMA main (2) hSem=CreateSemaphore(NULL,2,2,NULL); H1=CreateThread(0,0,THREAD_A,0,0,0); H2=CreateThread(0,0,THREAD_B,0,0,0); Sleep(5000); CloseHandle(H1); CloseHandle(H2); CloseHandle(hSem); printf("fin du main SEMA\n"); getchar(); return 0; }
59
jc/md/lp-01/06Synchronisation59 SEMA THREAD_A DWORD WINAPI THREAD_A(LPVOID p) { printf("debut du thread A\n"); WaitForSingleObject(hSem,INFINITE); printf("THREAD_A: le loup et l'agneau\n"); WaitForSingleObject(hSem,INFINITE); printf("THREAD_A: le lion et le rat\n"); ReleaseSemaphore(hSem,2,NULL); printf("fin du thread A\n"); return 0; }
60
jc/md/lp-01/06Synchronisation60 SEMA THREAD_B DWORD WINAPI THREAD_B(LPVOID p) { printf("debut du thread B\n"); Sleep(1000); //essayer en commentant la ligne WaitForSingleObject(hSem,INFINITE); printf("THREAD_B: la cerise sur le gateau\n"); ReleaseSemaphore(hSem,1,NULL); printf("fin du thread B\n"); return 0; }
61
jc/md/lp-01/06Synchronisation61 Résultat de lexécution avec délai
62
jc/md/lp-01/06Synchronisation62 Résultat de lexécution sans délai
63
jc/md/lp-01/06Synchronisation63 Résultat de lexécution perturbée
64
jc/md/lp-01/06Synchronisation64 Événements multiples Windows CE offre la possibilité de gérer plusieurs événements par la fonction WaitForMultipleObjects. Les principes sont similaires mais on utilise des événements enregistrés grâce à un tableau. Le premier élément activé rencontré joue le même rôle quun événement unique avec WaitForSingleObject.
65
jc/md/lp-01/06Synchronisation65 Conclusion Les différentes méthodes de synchronisation ont été appliquées sur des exemples concrets
Présentations similaires
© 2024 SlidePlayer.fr Inc.
All rights reserved.