Conditions dans les threads POSIX

pthread_cond_t

Le problème exposé dans ce sujet a été résolu.

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 :)

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.

+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.

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

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

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