Participer au site avec un Tip
Rechercher
 

Améliorations / Corrections

Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.

Emplacement :

Description des améliorations :

Fonction mtx_destroy (C ISO 2011)

La vidéo


Programmation multi-threads et gestion des accès concurrents

Entêtes à  inclure

#include <threads.h>

Fonction mtx_destroy

void mtx_destroy( mtx_t * mutex );

La fonction mtx_destroy permet de libérer les ressources acquises par un mutex. Le terme de mutex est un raccourci vers mutual exclusion. Un mutex est donc un mécanisme de synchronisation entre plusieurs threads qui cherchent à accéder, en parallèle, à une ressource partagée. Dans ce cas, ces accès concurrents peuvent amener à des incohérences si vous ne les synchronisez pas.

Cette fonction utilise un objet de type mtx_t qui correspond à l'instance de mutex à libérer. Libérer un mutex alors que des threads sont en attentes sur cette ressource provoque un comportement non défini.

Paramètre

Valeur de retour

Cette fonction ne renvoi pas de valeur de retour.

Exemple de code

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
 44 
 45 
 46 
 47 
#include <stdio.h>
#include <stdlib.h>
#include <threads.h>

#define THREAD_COUNT 10
#define THREAD_LOOP 1000000

// Une ressource partagée sur laquelle synchroniser nos threads.
mtx_t mutex;
unsigned long counter = 0;


// Définition de la fonction sur laquelle amorcer tous nos threads.
int threadFunction(void* data) {

    for( int i = 0; i<THREAD_LOOP; i++ ) {
        mtx_lock( &mutex );
        counter ++;
        mtx_unlock( &mutex );
    }

    printf( "Thread %ld terminé\n", (long) data );

    return thrd_success;
}

int main() {

    mtx_init( &mutex, mtx_plain );

    // On démarre tous nos threads sur la fonction définie ci-dessus.
    thrd_t threads[THREAD_COUNT];
    for( long i=0; i<THREAD_COUNT; i++ ) {
        thrd_create( &threads[i], threadFunction, (long *)i );
    }

    // On attend la terminaison de tous nos threads.
    for( int i=0; i<THREAD_COUNT; i++ ) {
        thrd_join( threads[i], NULL );
    }

    // Affichage du compteur et libération du mutex.
    printf( "Counter == %ld\n", counter );
    mtx_destroy( &mutex );

    return EXIT_SUCCESS;
}
Fichier sample.c : exemple d'utilisation d'un mutext

Pour compiler cet exemple sous environnement Linux/Unix, il est nécessaire de lier la librairie pthread (Posix Thread) à votre exécutable. Voici un exemple de compilation.

$> gcc -o sample sample.c -lpthread
$> ./sample
Thread 2 terminé
Thread 4 terminé
Thread 0 terminé
Thread 1 terminé
Thread 8 terminé
Thread 7 terminé
Thread 6 terminé
Thread 5 terminé
Thread 3 terminé
Thread 9 terminé
Counter == 10000000
$>

Normalement l'affichage de la valeur de compteur devrait être 10 000 000 (THREAD_COUNT * THREAD_LOOP). Maintenant pour bien comprendre l'intérêt du mutex, je vous demande de commenter les lignes 9, 17, 19, 29 et 44 (celles relatives à la gestion du mutex). Relancez plusieurs fois votre programme : normalement, la valeur du compteur devient imprédictible et donc on peut dire que notre programme ne marche plus.

Cela est dû au fait que l'instruction counter ++;, en ligne 18, n'est pas atomique. Elle correspond en vrai à trois instructions en langage machine : on charge la valeur de la variable en mémoire vers un registre du CPU, on incrémente la valeur de ce registre, et on recopie ce registre dans la zone mémoire associée à votre variable counter. En conséquence, imaginez qu'un premier thread arrive jusqu'à incrémenter la valeur du registre mais qu'il soit suspendu à ce moment-là, si un autre thread cherche aussi à incrémenter la variable counter, il ne constatera pas l'incrément précédent, vu qu'en mémoire on a toujours la valeur précédente. Si on utilise le mutex, l'incrément est donc garanti comme ne pouvant être joué que par un unique thread à la fois.

Fonctions et types connexes

mtx_init
mtx_lock
mtx_unlock
thrd_create