Conditions dans les threads POSIX

pthread_cond_t

L’auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Bonjour,

Dans le cadre d’un cours de programmation, j’essaye de tester les différentes possibilités de synchronisation entre threads possibles. L’exercice est un peu idiot: faire deux threads, un qui récupère les caractères entré, l’autre qui les compte (bref, producteur/consommateur). J’ai commencé par implémenter ça avec des mutex, et évidement, ça fonctionne. Puis on m’a demandé de tester avec pthread_cond_t. Et là, j’ai compris le principe (je crois), mais ça ne fonctionne pas.

 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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdbool.h>
#include <pthread.h>

int n = 0;
int total = 0;
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
bool producer_done = false, running = true;

void* read_chars(void* arg) {
    char c = 0;
    while(running) {
        pthread_mutex_lock(&mut);

        c = fgetc(stdin);

        if (c == '\n') {
            producer_done = true;
            pthread_cond_broadcast(&cond);
        }

        else if (c == '$') { // faut bien que j'arrête le programme à un moment
            running = false;
            pthread_cond_broadcast(&cond);
        }

        else
            n += 1;

        pthread_mutex_unlock(&mut);
    }
    pthread_exit(NULL);
}

void* count_chars(void* arg) {
    while(running) {
        pthread_mutex_lock(&mut);

        while(!producer_done) {
            pthread_cond_wait(&cond, &mut);
        }

        producer_done = false;
        total += n;
        n = 0;
        printf("counted: %d\n", total);

        pthread_mutex_unlock(&mut);
    }
    pthread_exit(NULL);
}

int main() {
    pthread_t threads[2];
    int i, res;

    res = pthread_create(&threads[1], NULL, count_chars, NULL);
    if (res != 0)
        perror("pthread_create");

    res = pthread_create(&threads[0], NULL, read_chars, NULL);
    if (res != 0)
        perror("pthread_create");

    for (i=0; i < 2; i++) {
        res = pthread_join(threads[i], NULL);
        if (res != 0)
            perror("pthread_join");
    }

    pthread_cond_destroy(&cond);
    pthread_mutex_destroy(&mut);

    exit(EXIT_SUCCESS);
}

Normalement, pthread_cond_wait(&cond, &mut) devrait s’endormir passer la main à l’autre thread (et en effet). Mais ensuite, pthread_cond_broadcast(&cond) devrait réveiller le thread en attente et le faire avancer. Et là … Non. Rien n’y fait, je n’ai jamais mon compte de caractère qui s’affiche, à part à la fin (quand je met un $, donc). Et quand je met un printf avant et après le broadcast, je vois qu’il a broadcasté, mais l’autre thread ne se réveille pas pour autant.

J’ai raté un truc ?

D’avance merci si vous savez m’expliquer ce que j’ai pas compris :)

#JeSuisToujoursArius • Doctorant et assistant en chimiedev' à temps partiel (co-réalisateur ZEP-12, recherche et template LaTeX)

+0 -0

Cette réponse a aidé l’auteur du sujet

En fait ton programme fonctionne comme attendu (imparable n’est-ce pas ?).

En fait pthread_cond_wait est sans doute bien réveillé lors de l’appel de pthread_cond_broadcast mais à ce moment là le thread read_chars a le mutex verrouillé pour lui, le déverrouille avant de le reverrouiller très vite après.

pthread_cond_wait ne s’arrêtera que lorsqu’il arrivera à reverrouiller le mutex ce qui apparemment n’arrive que lorsque ton thread read_chars s’arrête aussi.

Tu peux le voir si tu mets un temps de pause entre deux itérations de la boucle du thread en question. La fonction de comptage peut poursuivre dans ce cas.

Amateur de Logiciel Libre et de la distribution GNU/Linux Fedora. #JeSuisArius

+0 -0

Tout comme Renault. Avec les threads et les processus, tu ne sais pas quand ton thread est réveillé et tu ne peux pas t’attendre à un ordre particulier si tu ne synchronises pas toi-même explicitement, qui est la solution à ton problème.

+0 -0
Auteur du sujet

Ah, en effet. J’ai compris ce que je n’avais pas compris. Je partais du principe que pthread_cond_broadcast() allait magiquement faire reprendre l’exécution après le pthread_cond_wait(), alors qu’effectivement, il n’y a pas de raison de croire ça. Merci bien :)

[…] si tu ne synchronises pas toi-même explicitement, qui est la solution à ton problème.

Justement, on m’avais présenté ça comme une solution de synchronisation alternative. Bon, raison de plus pour que je reste avec mes mutexes :p

#JeSuisToujoursArius • Doctorant et assistant en chimiedev' à temps partiel (co-réalisateur ZEP-12, recherche et template LaTeX)

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte