section critique

Download Report

Transcript section critique

Processus et threads
1
Implémentation des processus
Différent champs d’une entrée de la table des processus
2
Création de processus sur UNIX
// Crée une copie exacte du processus appelant
pid_t fork(void)
// Remplace l’image du processus appelant
int execv(
const char *fichier,
char * const argv []
);
3
Valeur de retour
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status)
pid_t waitpid(
pid_t pid,
int *status,
int options);
4
Création de processus sur Windows (1)
BOOL WINAPI CreateProcess(
LPCTSTR lpApplicationName,
LPTSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
5
Création de processus sur Windows(2)
typedef struct _PROCESS_INFORMATION {
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
} *LPPROCESS_INFORMATION;
6
Fin d’exécution d’un processus
Conditions de fin d’exécution:
1. Sortie normale (volontaire)
2. Sortie avec erreur (volontaire)
3. Erreur fatale (involontaire)
4. Tué par un autre processus (involontaire)
7
L’état d’un processus
• États possibles
–
–
–
–
en cours d’exécution
bloqué
prêt
etc.
• Transitions entre les états
8
L’état d’un processus
Wikipedia
9
Les threads (1)
(a) Trois processus possédant un seul thread.
(b) Un processus possédant trois threads.
10
Les threads (2)
• Items partagés par tous les threads d’un processus
• Items à chaque thread
11
Les threads (3)
Chaque thread possède sa propre pile.
12
Utilisation des threads (1)
Un logiciel de traitement de texte avec trois threads
13
Les threads POSIX
#include <pthread.h>
int pthread_create(
pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void*),
void *restrict arg);
void pthread_exit(void *value_ptr);
int pthread_join(pthread_t thread, void **value_ptr);
14
Les threads POSIX
Certaines implémentations possèdent l’instruction:
void pthread_yield(void);
ou
void sched_yield(void);
Sur Solaris et Linux on compile avec l'option:
-lpthread
15
Les threads sur Windows
HANDLE WINAPI CreateThread(
__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in
SIZE_T dwStackSize,
__in
LPTHREAD_START_ROUTINE lpStartAddress,
__in_opt LPVOID lpParameter,
__in
DWORD dwCreationFlags,
__out_opt LPDWORD lpThreadId );
VOID WINAPI ExitThread( __in DWORD dwExitCode);
16
Les threads sur Windows
DWORD WINAPI WaitForSingleObject(
__in HANDLE hHandle,
__in DWORD dwMilliseconds );
DWORD WINAPI WaitForMultipleObjects(
__in DWORD nCount,
__in const HANDLE *lpHandles,
__in BOOL bWaitAll,
__in DWORD dwMilliseconds );
17
Communication interprocessus
Trois points importants:
• Comment partager les ressources?
• Concurrence pour l'utilisation des ressources
• Synchronisation
18
Conditions de concurrence
Deux processus veulent
accéder à la mémoire
partagée en même temps.
Par exemple: Les processus
A et B veulent utiliser la file
d’impression.
1.
2.
3.
A voit que la prochaine case disponible est 7 puis est remplacé par B
B voit que la prochaine case disponible est 7, y place le nom de son
fichier, puis est remplacé par A
A place le nom de son fichier dans une case qu’il croit libre écrasant le
nom donné par B
19
Sections Critiques (1)
L’exclusion mutuelle est une méthode qui permet de
s’assurer que si un processus utilise une variable ou un
fichier partagé, les autres processus seront exclus de la
même activité.
Une section critique (ou région critique) est la partie du
programme à partir de laquelle on accède à la mémoire
partagée.
20
Sections Critiques (2)
Quatre conditions pour obtenir l'exclusion mutuelle:
1.
2.
3.
4.
Un seul processus à la fois dans la section critique
Aucune supposition sur le nombre et la vitesse des CPUs
Aucun processus hors de la section critique ne peut
bloquer un autre processus.
Aucun processus ne doit attendre indéfiniment pour entrer
en section critique.
21
Sections critiques (3)
Exclusion mutuelle à l'aide des sections critiques.
22
Solutions à l’exclusion mutuelle
• Variable de verrou
• Un processus peut entrer seulement si VERROU=0
Il met alors VERROU=1 pour empêcher les autres
processus d’entrer
• Cette solution ne fonctionne pas sans aide
matérielle
23
L'instruction TSL (Test and Set Lock)
TSL R, LOCK est une opération atomique équivalente à:
R=LOCK
LOCK=1
enter_region:
TSL REGISTER,LOCK
CMP REGISTER,#0
JNE enter_region
RET
| copie lock dans le registre et le définit à 1
| lock était-il à 0 ?
| s'il n’était pas à 0, boucle
| retourne à l’appelant ; entre en section critique
leave_region:
MOVE LOCK,#0
RET
| stocke un 0 dans lock
| retourne à l’appelant
24
L'instruction XCHG (Intel x86)
XCHG R, LOCK échange le contenu de R et LOCK
Cette instruction peut facilement remplacer TSL
enter_region:
MOVE REGISTER, #1 | Mettre 1 dans REGISTER
XCHG REGISTER,LOCK | Échanger REGISTER et LOCK
CMP REGISTER,#0
| lock était-il à 0 ?
JNE enter_region
| s'il n’était pas à 0, boucle
RET
| retourne à l’appelant ; entre en section critique
leave_region:
MOVE LOCK,#0
RET
| stocke un 0 dans lock
| retourne à l’appelant
25
Opérations Sleep et Wakeup (1)
Alternative aux solutions par attente active vues jusqu’à présent.
Ex. Problème du producteur-consommateur
#define N 100
/* nombre de connecteurs dans le tampon */
int count = 0;
/* nombre d’éléments dans le tampon */
void producteur(void)
{
int item;
while (TRUE) {
item = produire_item( );
/* génère l’élément suivant */
if (count == N) sleep( );
/* si le tampon est plein, entre en sommeil */
ajouter_item(item);
/* place l’élément dans le tampon */
count = count + 1;
/* incrémente le décompte des éléments dans le tampon */
if (count == 1) wakeup(consommateur); /* le tampon était vide ? */
}
}
26
Opérations Sleep et Wakeup (2)
void consommateur(void)
{
int item;
while (TRUE) {
if (count == 0) sleep( );
/* si le tampon est vide, entre en sommeil */
item = enlever_item( );
/* prélève un élément dans le tampon */
count = count - 1;
/* décrémente le décompte des éléments dans le tampon */
if (count == N - 1) wakeup(producteur); /* le tampon était plein ? */
utiliser_item(item);
/* utilise l’élément */
}
}
Que se passe-t-il si le producteur fait un wakeup entre le
moment ou le consommateur constate que le tampon est vide et
celui où il appelle sleep?
27
Les sémaphores:
opérations Up et Down (1)
Solution de Dijkstra au problème des wakeup perdus.
Un sémaphore est une variable partagée entre plusieurs processus
et munie de deux nouvelles instruction atomiques:
Down(S):
if (S==0) sleep
S=S-1
Up(S):
S=S+1
if (S==1) wakeup() // si des processus sont endormis sur le
// sémaphore S alors l’un d’eux sera réveillé
28
Les sémaphores
Résolution au problème du producteur-consommateur.
On utilise trois sémaphores:
#define N 100
typedef int semaphore;
semaphore mutex = 1;
semaphore empty = N;
semaphore full = 0;
/* nombre d’emplacements dans le tampon */
/* les sémaphores sont un type de variable int spécial */
/* contrôle l’accès à la section critique */
/* compte les emplacements vides dans le tampon */
/* compte les emplacements pleins */
void producer(void){
int item;
while (TRUE) {
item = produce_item( ); /* génère quelque chose à placer dans le tampon */
down(&empty);
/* décrémente le décompte des emplacements vides */
down(&mutex);
/* entre en section critique */
insert_item(item);
/* place un nouvel élément dans le tampon */
up(&mutex);
/* quitte la section critique */
up(&full);
/* incrémente le décompte des emplacements pleins */
}
}
29
Les sémaphores
void consumer(void){
int item;
while (TRUE) {
down(&full);
/* décrémente le décompte des emplacements pleins */
down(&mutex);
/* entre en section critique */
item = remove_item(); /* prélève un élément dans le tampon */
up(&mutex);
/* quitte la section critique */
up(&empty);
/* incrémente le décompte des emplacements vides */
consume_item(item); /* fait quelque chose avec l’élément */
}
}
30
Sémaphores sur Windows
HANDLE WINAPI CreateSemaphore(
LPSECURITY_ATTRIBUTES lpsa,
LONG lInitialCount,
// Nombre de ressources initialement disponibles
LONG lMaximumCount, // Nombre maximale de ressources
LPCTSTR lpName
);
DWORD WINAPI WaitForSingleObject(
HANDLE hSemaphore,
DWORD dwMilliSeconds
// Peut être INFINITE
);
BOOL WINAPI ReleaseSemaphore(
HANDLE hSemaphore,
LONG lReleaseCount,
// Nombre de ressources à remettre
LPLONG lpPreviousCount // Reçoit le nombre de ressource actuelle);
31
Sémaphores sur Solaris
#include <semaphore.h>
sem_t *sem_open(
char* nom, // Le premier caractère du nom doit être '/'
int oflag // O_CREAT ou O_CREAT | O_EXCL
int mode // bits de permission
int valeur // valeur initiale
);
int sem_wait(sem_t *psem)
int sem_post(sem_t *psem)
int sem_init(
// sémaphore sans nom
sem_t * psem,
int pshare, // Si non nul, peut être partagé avec d'autres processus
int valeur // NULL = Attributs par défaut
);
32
Sémaphores sur Solaris
#include <semaphore.h>
main()
{
sem_t my_semaphore;
int rc;
rc = sem_init(&my_semaphore, 0, 10);
…
}
33
Les mutex
Les mutex sont des sémaphore qui ne peuvent
prendre que la valeur 0 ou 1. Ils servent à
réaliser l’exclusion mutuel.
34
Mutex sur Solaris
#include <pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int pthread_ mutex_lock(pthread_mutex_t* pm);
int pthread_mutex_unlock(pthread_mutex_t* pm);
int pthread_mutex_init( // mutex dynamique
pthread_mutex_t * pm,
const pthread_mutexattr_t *mattr // NULL = Attributs par défaut
);
35
Mutex sur Windows
HANDLE WINAPI CreateMutex (
LPSECURITY_ATTRIBUTES lpma, // Pour nos applications ce paramètre
// peut être mis à NULL
BOOL bInitialOwner,
// True pour créer et posséder le mutex
LPTSTR lpName // Nom pour partager le mutex avec d'autres processus
// ( Peut être NULL)
);
DWORD WINAPI WaitForSingleObject(
HANDLE hMutext,
DWORD dwMilliSeconds // Peut être INFINITE
);
BOOL WINAPI ReleaseMutex( HANDLE hMutex );
36
Critical Section sur Windows
void WINAPI InitializeCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
void WINAPI EnterCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
BOOL WINAPI InitializeCriticalSectionAndSpinCount(
LPCRITICAL_SECTION lpCriticalSection,
DWORD dwSpinCount
);
void WINAPI LeaveCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
37
Critical Section sur Windows
// Variable globale
CRITICAL_SECTION CriticalSection;
DWORD WINAPI ThreadProc( LPVOID lpParameter ){
...
EnterCriticalSection(&CriticalSection);
... // Accès à la ressource partagée.
LeaveCriticalSection(&CriticalSection);
...
}
void main(){
...
InitializeCriticalSection(&CriticalSection)
... // Création des threads
DeleteCriticalSection(&CriticalSection)
...
}
38
Variables conditionelles
Permet à un thread de se bloquer non pas à l’entrée d’une
région critique mais en fonction d’une certaine condition
définie par la valeur d’une variable.
Ex. Plusieurs threads se partage une variable P qu’ils
incrémentent à tour de rôle.
Un des threads veut se bloquer tant que P n’aura pas pas
atteint une certaine valeur.
39
Variables conditionelles sur Windows Vista
VOID WINAPI InitializeConditionVariable
PCONDITION_VARIABLE cond
);
BOOL WINAPI SleepConditionVariableCS(
PCONDITION_VARIABLE cond,
PCRITICAL_SECTION pcs,
DWORD millisecond
);
// De façon atomique, bloque et
// relâche la section critique
VOID WINAPI WakeConditionVariable(
PCONDITION_VARIABLE cond
);
// Débloque un thread bloqué
// sur la variable de condition
VOID WINAPI WakeAllConditionVariable(
bloqués
PCONDITION_VARIABLE cond
);
// Débloque tous les threads
// sur la variable de condition
40
Variables conditionelles sur Solaris
pthread-cond_t cond = PTHREAD_COND_INITIALIZER;
int pthread_cond_wait(
pthread_cond_t *cond,
pthread_mutex_t *mutex
);
int pthread-cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_init(
pthread_cond_t *cond,
const pthread_condattr_t *attr
);
41
Les barrières
• Utilisation des barrières
– Les processus s'approchent de la barrière
– Tous les processus sauf un sont bloqués
– Le dernier processus arrive, libérant les autres
42
Les barrières sur Solaris
int pthread_barrier_init(pthread_barrier_t * barrier,
const pthread_barrierattr_t * attr,
unsigned count);
int pthread_barrier_wait(pthread_barrier_t *barrier);
int pthread_barrier_destroy(pthread_barrier_t *barrier);
43