Bonjour à tous,

Voilà depuis quelques semaines j'étudie (en cours) la programmation système en C sous Linux. Ayant bien galéré à l'école, j'ai décidé de m'y replonger totalement pour bien comprendre et assimiler. Actuellement je bloque sur le TP "final" de la partie Threads et Sémaphore (Pour ceux qui connaisse il s'agit du Problème du dîner des philosophes).
Voici l'énoncé :
On rappelle qu’un nombre n (pour ma part n = 5) de philosophes sont assis autour d’une table ronde, sur laquelle sont installées n assiettes de spaghettis et n fourchettes. Chaque philosophe dispose d’une fourchette de chaque côté de son assiette.
Les philosophes commencent tous à penser. Lorsque l’un d’eux se décide à faire une pause pour manger, il cherche à prendre les deux fourchettes qui se trouvent de chaque côté de son assiette. Si un de ses voisins mange, il devra attendre… Si une des deux fourchettes est occupée par un voisin, il devra attendre. Le programme prend fin dès que NBCYCLES cycles penser-manger ont été réalisés par chaque philosophe. L'affichage devra se faire sur une seule ligne représentant l'état de chaque Philosophe (P P P P P). On doit afficher seulement quand il y a Changement d'Etat d'1 Philosophe (P P P P P , P P P P A, P P P P M, P P P A M, etc...).
Le schéma du système :

Bien sûr ce système est connu pour être bloquant. J'ai donc choisi d'utiliser un tableau de sémaphores "privé", 1 pour chaque philosophe en attente de ses fourchettes. Les états des philosophes sont stockés dans un tableau. J'utilise donc un sémaphore "public" de type mutex pour la section critique Tableau d'état.
Déjà voilà mon code :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/**************************************
** pthread-philo2.c
**
** Programme d'exemple de pthread avec
** philosophes qui dinent et mutex
**
***************************************/
 
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <semaphore.h>
#include <errno.h>
#include <string.h>
 
#define NB_PHILO 5
#define NB_CYCLE 5
 
typedef enum{Pense, Mange, Attend} T_etat;
 
T_etat etatPhilo[NB_PHILO];
 
static sem_t fourchettes[NB_PHILO]; // sémaphore privé, sémaphore pour les ressources fourchettes (1 par philosophe)
static sem_t SemaPublic; // pour l'affichage (il faut pas que ça change pendant qu'on affiche)
 
 
 
void error(int err, char *msg) {
    fprintf(stderr,"%s a retourné %d message d'erreur : %s\n",msg,err,strerror(errno));
    exit(EXIT_FAILURE);
}
 
void changeEtaffiche ( int* id, T_etat nouvelEtat)  // fonction affichant les états des différents philosophes sur une ligne
{
    int i;
    sem_wait(&SemaPublic);
    etatPhilo[*id] = nouvelEtat;
    for (i = 0; i<NB_PHILO; i++)
    {
        switch(etatPhilo[i]){
            case Pense: printf(" P "); break;
            case Mange: printf(" M "); break;
            case Attend: printf(" A "); break;
        }
    }
    printf("\n\n");
    sem_post(&SemaPublic);
}
 
 
 
void* philosophe ( void* arg )
{
    int *id=(int *) arg;
    int left = *id;
    int right = (left + 1) % NB_PHILO;
 
    int cycle;
    for(cycle=0; cycle<NB_CYCLE; cycle++) {
 
        // il attend
        changeEtaffiche(id,Attend);
        if(left<right) {
            sem_wait(&fourchettes[left]);
            sem_wait(&fourchettes[right]);
        }
        else {
            sem_wait(&fourchettes[right]);
            sem_wait(&fourchettes[left]);
        }
 
        // il mange
        changeEtaffiche(id,Mange);
        //sleep(2);
 
        // il pense (important: avant de relacher ses fourchette, parce que s'il le fait après, l'affichage mettrait que 2 voisins mange en même temps)
        changeEtaffiche(id,Pense);
        sem_post(&fourchettes[left]);
        sem_post(&fourchettes[right]);
 
        //sleep(2);
 
    }
    return (NULL);
}
 
/*********************
***** MAIN
*********************/
int main ( int argc, char *argv[])
{
    int i;
    int id[NB_PHILO];
    int err;
    pthread_t thread[NB_PHILO]; // threads philosophes
 
    srand(getpid());
 
    sem_init(&SemaPublic,0,1);
 
    for (i = 0; i < NB_PHILO; i++) {
        id[i]=i;
        etatPhilo[i] = Pense;       // au début TOUS les philosophes pensent
        err=sem_init( &fourchettes[i], 0, 1);
        if(err!=0)
            error(err,"sem_init");
    }
 
    for (i = 0; i < NB_PHILO; i++) {
        err=pthread_create(&thread[i], NULL, philosophe, (void*)&(id[i]) );
        if(err!=0)
            error(err,"pthread_create");
    }
 
    for (i = 0; i < NB_PHILO; i++) {
        pthread_join(thread[i], NULL);
        if(err!=0)
            error(err,"pthread_join");
    }
 
    for (i = 0; i < NB_PHILO; i++) {
        sem_destroy(&fourchettes[i]);
        if(err!=0)
            error(err,"pthread_mutex_destroy");
    }
 
    sem_destroy(&SemaPublic);
 
    return (EXIT_SUCCESS);
}
Ce code compile et s'exécute.
J'ai plusieurs problèmes :
1. Déjà je n'arrive pas à afficher QUE quand il y a changement d'état d'un philosophe (vous verrez qu'on a un affichage de 5 lignes en même temps et plusieurs fois la même ligne s'affiche à la suite)
2. J'ai l'impression que plusieurs philosophes ne peuvent pas manger en même temps (alors que par exemple philo 0 et philo 2 pourraient..) et à chaque fois j'ai une ligne où les 5 philosophes attendent et ce toutes les 3 lignes affichées.
3. Je n'arrive pas à gérer le fait que quand chaque philosophe aura manger X fois il reste en état pense et que quand tous les philos ont mangés X fois et sont en état Pense, le programme se termine.

Pour mes 1ère et 2è questions c'est au niveau des sémaphores que cela se passe je le sais. Et c'est sur cette partie que je bloque le plus, donc hésitez pas à critiquer mon code et surtout à bien m'expliquer pourquoi ça plutôt que comme moi j'ai fait.
Je veux vraiment afficher une ligne quand UN etat d'UN philosophe change et je ne veux pas que ca fasse les philosophes les uns après les autres (n°0 mange, puis pense, n°1 mange puis pense etc..) comme cela fait quand on exécute mon code.

Désolé de la taille du poste (j'aime bien détailler et expliquer ce que je veux vraiment). Si vous avez mal compris des choses, demandez ^^
Merci d'avance à ceux qui prendront le temps de me lire et de me répondre
Je compte sur votre aide^^
Cordialement,
Fuot