Introduction à la programmation concurrente



Documents pareils
Introduction à la programmation concurrente

4. Outils pour la synchronisation F. Boyer, Laboratoire Lig

INTRODUCTION AUX SYSTEMES D EXPLOITATION. TD2 Exclusion mutuelle / Sémaphores

Les processus légers : threads. Système L3, /31

INTRODUCTION À LA PROGRAMMATION CONCURRENTE

J2SE Threads, 1ère partie Principe Cycle de vie Création Synchronisation

03/04/2007. Tâche 1 Tâche 2 Tâche 3. Système Unix. Time sharing

Exclusion Mutuelle. Arnaud Labourel Courriel : arnaud.labourel@lif.univ-mrs.fr. Université de Provence. 9 février 2011

4. Outils pour la synchronisation F. Boyer, Laboratoire Sardes

Problèmes liés à la concurrence

Éléments d informatique Cours 3 La programmation structurée en langage C L instruction de contrôle if

Cours de Systèmes d Exploitation

Cours 2: Exclusion Mutuelle entre processus (lourds, ou légers -- threads)

Info0604 Programmation multi-threadée. Cours 5. Programmation multi-threadée en Java

École Polytechnique de Montréal. Département de Génie Informatique et Génie Logiciel. Cours INF2610. Contrôle périodique.

Threads. Threads. USTL routier 1

Introduction : les processus. Introduction : les threads. Plan

Prénom : Matricule : Sigle et titre du cours Groupe Trimestre INF1101 Algorithmes et structures de données Tous H2004. Loc Jeudi 29/4/2004

Exercices INF5171 : série #3 (Automne 2012)

Notion de thread (1/2)

Synchro et Threads Java TM

as Architecture des Systèmes d Information

1 Mesure de la performance d un système temps réel : la gigue

Bases de programmation. Cours 5. Structurer les données

Introduction à Java. Matthieu Herrb CNRS-LAAS. Mars

Cours de C++ François Laroussinie. 2 novembre Dept. d Informatique, ENS de Cachan

Un ordonnanceur stupide

Cours d Algorithmique-Programmation 2 e partie (IAP2): programmation 24 octobre 2007impérative 1 / 44 et. structures de données simples

Exécutif temps réel Pierre-Yves Duval (cppm)

Introduction aux systèmes temps réel. Iulian Ober IRIT

4. Groupement d objets

Programmer en JAVA. par Tama

Projet de programmation (IK3) : TP n 1 Correction

Cours d Algorithmique et de Langage C v 3.0

1/24. I passer d un problème exprimé en français à la réalisation d un. I expressions arithmétiques. I structures de contrôle (tests, boucles)

1.6- Génération de nombres aléatoires

Les structures de données. Rajae El Ouazzani

Processus! programme. DIMA, Systèmes Centralisés (Ph. Mauran) " Processus = suite d'actions = suite d'états obtenus = trace

Cette application développée en C# va récupérer un certain nombre d informations en ligne fournies par la ville de Paris :

Projet gestion d'objets dupliqués

Programmation avec des objets : Cours 7. Menu du jour

1. Structure d un programme C. 2. Commentaire: /*..texte */ On utilise aussi le commentaire du C++ qui est valable pour C: 3.

Cours Programmation Système

INITIATION AU LANGAGE JAVA

Cours Bases de données 2ème année IUT

Algorithmique et Programmation, IMA

Programmation d Applications Concurrentes et Distribuées (INF431)

INFO-F-105 Language de programmation I Séance VI

LOG4430 : Architecture et conception avancée

On appelle variable condition une var qui peut être testée et

2. Comprendre les définitions de classes

INITIATION AU LANGAGE C SUR PIC DE MICROSHIP

Cours d initiation à la programmation en C++ Johann Cuenin

Les Threads. Sommaire. 1 Les Threads

TD3: tableaux avancées, première classe et chaînes

Programmation C++ (débutant)/instructions for, while et do...while

Licence Bio Informatique Année Premiers pas. Exercice 1 Hello World parce qu il faut bien commencer par quelque chose...

Cours de Base de Données Cours n.12

Gestion des transactions et accès concurrents dans les bases de données relationnelles

Programme Compte bancaire (code)

Informatique III: Programmation en C++

Temps Réel. Jérôme Pouiller Septembre 2011

IN Cours 1. 1 Informatique, calculateurs. 2 Un premier programme en C

Plan du cours. Historique du langage Nouveautés de Java 7

DAns un système d exploitation multiprogrammé en temps partagé, plusieurs


TP 1. Prise en main du langage Python

TD2 Programmation concurrentielle

Exceptions. 1 Entrées/sorties. Objectif. Manipuler les exceptions ;

Conventions d écriture et outils de mise au point

Introduction aux Systèmes et aux Réseaux

Claude Delannoy. 3 e édition C++

DAns un système multi-utilisateurs à temps partagé, plusieurs processus

Recherche dans un tableau

IFT Systèmes d exploitation - TP n 1-20%

Classe ClInfoCGI. Fonctions membres principales. Gestion des erreurs

Une introduction à Java

TP n 2 Concepts de la programmation Objets Master 1 mention IL, semestre 2 Le type Abstrait Pile

Systèmes temps-réel. Plan général. Matthieu Herrb. Mars Introduction - concepts généraux

Performances de la programmation multi-thread

Java Licence Professionnelle CISII,

Cours intensif Java. 1er cours: de C à Java. Enrica DUCHI LIAFA, Paris 7. Septembre Enrica.Duchi@liafa.jussieu.fr

M2-Images. Rendu Temps Réel - OpenGL 4 et compute shaders. J.C. Iehl. December 18, 2013

Organigramme / Algorigramme Dossier élève 1 SI

#include <stdio.h> #include <stdlib.h> struct cell { int clef; struct cell *suiv; };

Notions fondamentales du langage C# Version 1.0

Pour plus de détails concernant le protocole TCP conférez vous à la présentation des protocoles Internet enseignée pendant.

Contrôle de versions et travail collaboratif. Organisation du travail collaboratif. Organisation du travail collaboratif

EPREUVE OPTIONNELLE d INFORMATIQUE CORRIGE

Auto-évaluation Programmation en Java

TP : Gestion d une image au format PGM

Une introduction à la technologie EJB (2/3)

Premiers Pas en Programmation Objet : les Classes et les Objets

Quelques patterns pour la persistance des objets avec DAO DAO. Principe de base. Utilité des DTOs. Le modèle de conception DTO (Data Transfer Object)

Utilisation d objets : String et ArrayList

Corrigés des premiers exercices sur les classes

Processus, threads et gestion de la synchronisation

TP3 : Manipulation et implantation de systèmes de fichiers 1

Programmation MacOSX / ios

Transcription:

à la programmation concurrente et sémaphores Yann Thoma Reconfigurable and Embedded Digital Systems Institute Haute Ecole d Ingénierie et de Gestion du Canton de Vaud This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License Février 2015 Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 1 / 38 L attente active a un énorme désavantage: Réquisition du processeur Solution: les verrous Le verrou est une variable booléenne possède une liste d attente est manipulé par deux opérations atomiques: Verrouille(v) Deverrouille(v) En anglais: mutex, pour mutual exclusion Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 2 / 38

Pseudocode des deux opérations void Verrouille(verrou v) { if (v) v = false; else suspendre la tâche appelante dans la file associée à v void Déverrouille(verrou v) { if (la file associée à v!= vide) débloquer une tâche en attente dans file else v = true; Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 3 / 38 - Points importants Un mutex possède un "propriétaire" : le thread ayant obtenu le verrou est le propriétaire du mutex jusqu à ce qu il le déverrouille : le thread ayant verrouillé le mutex est responsable de le déverrouiller (relâcher); un thread ne peut pas déverrouiller un mutex déjà verrouillé par un autre thread. Les fonctions lock et unlock sont atomiques! Verrouiller un mutex déjà verrouillé bloque le thread appelant deadlock assuré si un même thread verrouille un mutex de façon consécutive (sauf pour les mutex récursifs). Déverrouiller un mutex plusieurs fois n a pas d effet pas de "mémoire" du nombre de fois qu un mutex a été déverrouillé (sauf pour les mutex récursifs). Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 4 / 38

Utilisation des verrous: Section critique Une section critique peut être protégée par un verrou Pour un nombre quelconque de tâches. Verrouille(v); /* section critique */ Déverrouille(v);. Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 5 / 38 Mauvaise utilisation des verrous Illégal mutex m; Un thread ne peut pas déverrouiller un verrou déjà verrouillé par un autre thread! void *thread_a(void *p) { unlock(m); int main() { mutex_init(m); lock(m); create_thread(thread_a); Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 6 / 38

Qt Une classe verrou: QMutex Utilisation : #include<qmutex> Des fonctions lock() unlock() trylock(int timeout = 0) Initialisation: Constructeur: QMutex(RecursionMode mode = NonRecursive) Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 7 / 38 Pour la culture: POSIX Un type verrou: pthread_mutex_t Des fonctions pthread_mutex_lock(pthread_mutex_t *mutex) pthread_mutex_unlock(pthread_mutex_t *mutex) pthread_mutex_trylock(pthread_mutex_t *mutex) Initialisation: pthread_mutex_init() pthread_mutex_t m=pthread_mutex_initializer; Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 8 / 38

Qt: Initialisation Déclaration et initialisation faites de manière implicite via le constructeur: QMutex mutex; QMutex mutex(qmutex::recursive); Mutex récursif Après initialisation un mutex est toujours déverrouillé Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 9 / 38 Qt: Verrouillage void QMutex::lock(); Si le mutex est déverrouillé, il devient verrouillé et son propriétaire est alors le thread appelant. Mutex récursif: peut être verrouillé plusieurs fois; un compteur mémorise le nombre de verrouillages effectués. Mutex non récursif: Si un thread tente de reverouiller un mutex vérouillé par lui il y a deadlock. Si le mutex est déjà verrouillé par un autre thread, le thread appelant est suspendu jusqu à ce que le mutex soit déverrouillé. Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 10 / 38

Qt: Verrouillage bool QMutex::tryLock(int timeout = 0); Même comportement que lock, sauf qu il n y a suspension du thread appelant seulement pendant timeout millisecondes La fonction retourne true si le verrou a été acquis et false s il est possédé par un autre thread. Dans le cadre du cours, nous laisserons timeout à 0. Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 11 / 38 Qt: Déverrouillage void QMutex::unlock(); Déverrouille (libère) le mutex; le mutex est supposé être verrouillé par le thread appelant avant l appel à unlock(). Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 12 / 38

Qt: exemple static QMutex mutex; static int global=0; class MyThread : public QThread { void run() { for(int i=0;i<1000000;i++) { mutex.lock(); global = global + 1; mutex.unlock(); int main(void) { MyThread tache1, tache2; tache1.start(); tache2.start(); tache1.wait(); tache2.wait(); std::cout << "Fin des taches : global = " << global << " (" << 2*iterations << ")" << std::endl; return 0; Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 13 / 38 Qt: exemple static QMutex mutex; static int global=0; class MyThread : public QThread { void run() { for(int i=0;i<1000000;i++) { if (mutex.trylock()) { global = global + 1; std::cout << "I got the mutex" << std::endl; mutex.unlock(); Ne pas oublier else std::cout << "I cannot get the mutex" << std::endl; int main(void) { MyThread tache1, tache2; tache1.start(); tache2.start(); tache1.wait(); tache2.wait(); std::cout << "Fin des taches : global = " << global << " (" << 2*iterations << ")" << std::endl; return 0; Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 14 / 38

Attention Un verrou doit être libéré par le thread qui l a acquis!! La solution pour la synchronisation est d utiliser des sémaphores... Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 15 / 38 Les sémaphores sont une généralisation des verrous Proposés par Dijkstra en 62 ou 63 (article en hollandais) Comprennent une variable entière plutôt qu un booléen Opérations d accès (atomiques): P(s) (pour tester: Prolaag (probeer te verlagen: essayer de réduire)) V(s) (pour incrémenter: Verhoog) Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 16 / 38

Pseudocode des deux opérations void P(sémaphore s) { s -= 1; if (s < 0) suspendre la tâche appelante dans la file associée à s void V(sémaphore s) { s += 1; if (s <= 0) débloquer une des tâches de la file associée à s Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 17 / 38 Section critique Une section critique peut être protégée par un sémaphore Pour un nombre quelconque de tâches Un sémaphore mutex initialisé à 1. P(mutex); /* section critique */ V(mutex);. Sémaphore mutex initalisé à v > 0 jusqu à v tâches peuvent être admises simultanément dans la section critique section contrôlée Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 18 / 38

Qt Une classe sémaphore: QSemaphore Utilisation : #include<qsemaphore> Des fonctions Constructeur: QSemaphore(int n=0) acquire(int n=1) release(int n=1) A éviter: tryacquire(int n=1) int available() const Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 19 / 38 Pour la culture: Posix Un type sémaphore: sem_t Des fonctions sem_init(sem_t *sem,int pshare, unsigned int value) sem_destroy(sem_t *sem) sem_wait(sem_t *sem) sem_post(sem_t *sem) A éviter: sem_trywait(sem_t *sem) sem_getvalue(sem_t *sem,int *sval) Fichier à inclure: #include <semaphore.h> Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 20 / 38

: Création et destruction Constructeur QSemaphore::QSemaphore(int n = 0); Crée un sémaphore et l initialise à la valeur spécifiée; Dans le cadre du cours, interdiction de l initialiser à une valeur négative Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 21 / 38 : Attente void acquire(int n=1); Décrémente (bloque) le sémaphore spécifié. Si la valeur du sémaphore est > 0, sa valeur est décrémentée et la fonction retourne immédiatement; Si sa valeur est égal à 0, alors l appel bloque jusqu à ce que sa valeur devienne > 0; Dans le cadre du cours, interdiction d utiliser n > 1. Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 22 / 38

: Attente bool tryacquire(int n=1); Identique à acquire, sauf que si la décrémentation ne peut pas avoir lieu, la fonction renvoie false au lieu de bloquer Renvoie true en cas de succès et false si la valeur du sémaphore est plus petite ou égale à 0. Dans le cadre du cours, interdiction d utiliser n > 1. Nous n utiliserons pas cette fonction dans ce cours. Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 23 / 38 : Signalisation void release(int n=1); Incrémente (débloque) le sémaphore spécifié; Si la valeur du sémaphore devient > 0, alors un autre thread bloqué dans un appel à acquire sera débloqué de la file d attente et pourra effectuer l opération de décrémentation (déblocage); Dans le cadre du cours nous n utiliserons pas de valeur de n > 1. Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 24 / 38

: exemple #define NUM_THREADS 4 QSemaphore *sem; MyThread : public QThread { int tid; MyThread(int id) : tid(id) {; void run() { sem->acquire(); cout << "Tache " << tid << " est rentrée en SC" << endl; sleep((int)((float)3*rand()/(rand_max+1.0))); cout << "Tache " << tid << " sort de la SC" << endl; sem->release(); int main(void) { int i; QThread *threads[num_threads]; sem = new QSemaphore(2); for (i = 0; i < NUM_THREADS; i++) { threads[i] = new MyThread(i); threads[i]->start(); for (i = 0; i < NUM_THREADS; i++) threads[i]->wait(); return EXIT_SUCCESS; Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 25 / 38 Exemple: gestion des imprimantes Gestion de N imprimantes Un objet responsable d allouer une imprimante à un job d impression N allocations possibles avant blocage; void test() { PrinterManager *manager = new PrinterManager(5); // 5 printers int index1 = manager->allocate(); int index2 = manager->allocate(); // Do some printing manager->giveback(index2); manager->giveback(index1); Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 26 / 38

Exemple: gestion des imprimantes Gestion de N imprimantes class PrinterManager { QSemaphore *nbprinterssem; bool *occupee; PrinterManager(int nbprinters) { nbprinterssem = new QSemaphore(nbPrinters); occupee = new bool[nbprinters]; ~PrinterManager() { delete nbprinterssem; delete[] occupee;... unsigned giveindex(void) { unsigned compteur = 0; // Recherche de la 1ère imprimante libre while (occupee[compteur]) compteur += 1; occupee[compteur] = true; return compteur; unsigned allocate(void) { nbprinterssem->acquire(); return giveindex(); void giveback(unsigned index) { occupee[index] = false; nbprinterssem->release(); Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 27 / 38 Exemple: gestion des imprimantes Gestion de N imprimantes nbprinterssem est initialisé à N; N allocations possibles avant blocage; exécution concurrente de la fonction giveindex : problèmes d exclusion mutuelle sur le tableau occupee; mettre giveindex en section critique. Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 28 / 38

Exemple: gestion des imprimantes (solution correcte) class PrinterManager { QSemaphore *nbprinterssem; bool *occupee; QSemaphore *mutex; PrinterManager(int nbprinters) { nbprinterssem = new QSemaphore(nbPrinters); mutex = new QSemaphore(1); occupee = new bool[nbprinters]; ~PrinterManager() { delete nbprinterssem; delete mutex; delete[] occupee;... unsigned giveindex(void) { unsigned compteur = 0; mutex->acquire(); // Recherche de la 1ère imprimante libre while (occupee[compteur]) compteur += 1; occupee[compteur] = true; mutex->release(); return compteur; unsigned allocate(void) { nbprinterssem->acquire(); return giveindex(); void giveback(unsigned index) { occupee[index] = false; nbprinterssem->release(); Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 29 / 38 Exemple: gestion des imprimantes Cette solution est-elle correcte? class PrinterManager { QSemaphore *nbprinterssem; bool *occupee; QSemaphore *mutex; PrinterManager(int nbprinters) { nbprinterssem = new QSemaphore(nbPrinters); mutex = new QSemaphore(1); occupee = new bool[nbprinters]; ~PrinterManager() { delete nbprinterssem; delete mutex; delete[] occupee;... unsigned giveindex(void) { unsigned compteur = 0; // Recherche de la 1ère imprimante libre while (occupee[compteur]) compteur += 1; occupee[compteur] = true; mutex->release(); return compteur; unsigned allocate(void) { mutex->acquire(); nbprinterssem->acquire(); return giveindex(); void giveback(unsigned index) { occupee[index] = false; nbprinterssem->release(); Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 30 / 38

Coordination Coordination de tâches Les sémaphores peuvent servir à coordonner/synchroniser des tâches Exemple: La tâche T1 exécute les instructions I 1 La tâche T2 exécute les instructions I 2 L exécution de I 1 doit se faire avant I 2 Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 31 / 38 Coordination Coordination de tâches: exemple void T1::run() { std::cout << "T1: I1" << std::endl; return; void T2::run() { std::cout << "T2: I2" << std::endl; return; // I_1 // I_2 int main(void) { T1 tache1; T2 tache2; tache1.start(); tache2.start(); tache1.wait(); tache2.wait(); return 0; Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 32 / 38

Coordination Coordination de tâches: exemple static QSemaphore sync(0); void T1::run() { sleep(1); std::cout << "T1: fini sleep\n"; sync.release(); // I_1 void T2::run() { std::cout << "T2: avant acquire\n"; sync.acquire(); std::cout << "T2: apres acquire\n"; // I_2 int main(void) { T1 tache1;t2 tache2; tache1.start(); tache2.start(); tache1.wait(); tache2.wait(); return 0; Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 33 / 38 Rendez-vous Coordination Deux tâches se donnent rendez-vous entre deux activités respectives TâcheA TâcheB Premières activités a1 b1 Rendez-vous Deuxièmes activités a2 b2 Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 34 / 38

Première solution Coordination static QSemaphore arrivea(0); static QSemaphore arriveb(0); void MyThreadA::run() { a1; arriveb.acquire(); arrivea.release(); a2; return NULL; void MyThreadB::run() { b1; arriveb.release(); arrivea.acquire(); b2; return NULL; int main(void) { MyThreadA tachea;mythreadb tacheb; tachea.start(); tacheb.start(); tachea.wait(); tacheb.wait(); return 0; Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 35 / 38 Deuxième solution Coordination... void MyThreadA::run() { a1; arrivea.release(); arriveb.acquire(); a2; return NULL; void MyThreadB::run() { b1; arriveb.release(); arrivea.acquire(); b2; return NULL;... Comparaison des deux solutions... Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 36 / 38

Exercices Exercices 1 Comment implémentez-vous un verrou si vous ne disposez que de sémaphores? La sémantique du verrou doit évidemment être préservée. 2 Commentez la différence entre les deux codes suivants: void *tache(void *) { QMutex mutex; mutex.acquire(); std::cout << "Section critique\n"; mutex.release(); void *tache(void *) { static QMutex mutex; mutex.acquire(); std::cout << "Section critique\n"; mutex.release(); Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 37 / 38 Exercice Exercices Nous désirons réaliser une application possédant 2 tâches. Le programme principal est en charge de lancer les deux tâches. Etant donné que les tâches, une fois lancées, doivent attendre un signal du programme principal pour s exécuter, comment résoudre le problème à l aide de sémaphores? Y. Thoma (HES-SO / HEIG-VD / REDS) à la programmation concurrente Février 2015 38 / 38