IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

POSIX C Discussion :

Comment "dire" aux threads de se terminer


Sujet :

POSIX C

  1. #1
    Membre du Club
    Inscrit en
    Mai 2005
    Messages
    77
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 77
    Points : 58
    Points
    58
    Par défaut Comment "dire" aux threads de se terminer
    Bonjour à tous
    Je débute les threads et j'ai pris pas mal de tutoriels et d'exemples pour essayer de faire les choses simplements. Le programme qui suit est très largement inspiré de F.Hecht.
    Voici ce qu'il fait : une tache mère récupère une liste d'instructions à exécuter. A chaque fois qu'un thread lui demande une commande, la tache mère lui donne jsuqu'à ce qu'il n'y ait plus rien à faire. Et c'est là où je cale... mes threads restent bloqués en attente d'une tache. J'ai vu que je pouvais utiliser le "pthread_cond_broadcast" pour réveiller tous les threads d'un coup et donc de leur dire de se terminer, mais je ne vois pas comment faire...
    Voici le code, j'espère que vous pourrez m'aider.
    Iza

    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
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
    #include <string.h>
    #include <windows.h>
     
     
    #define psleep(sec) Sleep ((sec) * 1000)
     
     
    #define NB_THREADS      5
     
    struct MaillonToExecute
    {
    	struct MaillonToExecute *MaillonNext;
    	char Commande[80];
    };
     
    /* Structure stockant les informations des threads et de la tache mère. */
    typedef struct
    {
        char Commande[80];
    	BOOL KillAllThreads;
     
        pthread_t Thread_Mere;
        pthread_t Thread_Fils [NB_THREADS];
     
        pthread_mutex_t Mutex_Commande;
        pthread_cond_t Cond_Commande;
        pthread_cond_t Cond_Exec;
        pthread_cond_t Cond_Die;
    }
    Threads;
     
    static Threads Threads_t ;
     
    /* Fonction pour tirer un nombre au sort entre 0 et max. */
    int get_random (int max)
    {
       double val;
     
       val = (double) max * rand ();
       val = val / (RAND_MAX + 1.0);
     
       return ((int) val);
    }
     
     
    /* Fonction pour le thread mere. */
    void * fn_getliste(void *p_data)
    {
    	FILE *HandleRun;
    	char *FileName="FileCommand.txt";
    	char Line[80]=" ";
    	char *PtrString;
    	struct MaillonToExecute *ListeToExecute,*Maillon,*Ptr;
    	BOOL ReadOne=TRUE;
     
    	if(HandleRun=fopen(FileName,"rb"))
    	{	
    		while(fgets(Line,sizeof(Line),HandleRun))
    		{
    			if(Maillon=(struct MaillonToExecute *)calloc(1,sizeof(struct MaillonToExecute)))
    			{
    				sprintf(Maillon->Commande,"%s",Line);
    				if(PtrString=strchr(Maillon->Commande,'\n')) *PtrString='\0';
    				if(PtrString=strchr(Maillon->Commande,'\r')) *PtrString='\0';
    				Maillon->MaillonNext=NULL;
    				if(ReadOne)
    				{
    					ListeToExecute=Maillon;
    					ReadOne=FALSE;
    				}else
    				{
    					Ptr->MaillonNext=Maillon;
    				}
    				Ptr=Maillon;	
    			}
    		}
    		fclose(HandleRun);
    	}
     
    	printf("Fin lecture\n");
    	Maillon=ListeToExecute;
    	while(Maillon)
    	{
    	  /* Debut de la zone protegee. */
    	  pthread_mutex_lock(&Threads_t.Mutex_Commande);
    	  pthread_cond_wait(&Threads_t.Cond_Commande,&Threads_t.Mutex_Commande);
     
    	  sprintf(Threads_t.Commande,"%s",Maillon->Commande);
    	  printf("Mise a dispo de la %s \n",Threads_t.Commande);
     
    	  pthread_cond_signal(&Threads_t.Cond_Exec);
    	  pthread_mutex_unlock (&Threads_t.Mutex_Commande);
    	  /* Fin de la zone protegee. */
     
    	  Ptr=Maillon;
    	  Maillon=Maillon->MaillonNext;
    	  free(Ptr);
    	}
     
    	Threads_t.KillAllThreads=TRUE;
     
    	pthread_cond_broadcast(&Threads_t.Cond_Die);
    	return NULL;
    }
     
     
    /* Fonction pour les threads. */
    void * fn_threads(void *p_data)
    {
    	int nb=(int)p_data,sec;
     
    	printf("Thread %ld\n",nb);
    	while(!Threads_t.KillAllThreads)
    	{
    		/* Debut de la zone protegee. */
    		pthread_mutex_lock(&Threads_t.Mutex_Commande);
     
    		if(!strncmp(Threads_t.Commande,"\0",1))
    		{
    			pthread_cond_signal(&Threads_t.Cond_Commande);
    			printf("thread %ld demande commande\n",nb);
    			pthread_cond_wait(&Threads_t.Cond_Exec,&Threads_t.Mutex_Commande);
    			printf("thread %ld continue\n",nb);
    		}
    		printf("Execution de la %s par thread %ld\n",Threads_t.Commande,nb);
    		strncpy(Threads_t.Commande,"\0",1);
    		pthread_mutex_unlock(&Threads_t.Mutex_Commande);
    		/* Fin de la zone protegee. */
    		sec=get_random(10);
    		printf("Attente pour thread %ld de %ld secondes\n",nb,sec);
    		psleep(sec); 
    		printf("Fin attente pour thread %ld\n",nb);
    	}
    	return NULL;
    }
     
     
    int main (void)
    {
    	int i = 0;
    	int ret = 0;
     
    	pthread_mutex_init(&Threads_t.Mutex_Commande,NULL);
    	pthread_cond_init(&Threads_t.Cond_Commande,NULL);
    	pthread_cond_init(&Threads_t.Cond_Exec,NULL);
    	strncpy(Threads_t.Commande,"\0",1);
    	Threads_t.KillAllThreads=FALSE;
     
    	/* Creation des threads. */
    	printf ("Creation du thread mere !\n");
    	ret=pthread_create(&Threads_t.Thread_Mere,NULL,fn_getliste,NULL);
     
    	/* Creation des threads si le process mère a fonctionné. */
    	if (!ret)
    	{
    		printf ("Creation des threads fils !\n");
    		for (i=0;i<NB_THREADS;i++)
    		{
    			ret=pthread_create(&Threads_t.Thread_Fils[i],NULL,fn_threads,(void *)i);
    			if (ret)
    			{
    				printf ("%s",strerror(ret));
    			}
    		}
    	}else	
    	{
    		printf("%s",strerror(ret));
    	}
     
     
    	/* Attente de la fin des threads. */
    	i=0;
    	for (i=0;i<NB_THREADS;i++)
    	{
    		pthread_join(Threads_t.Thread_Fils[i],NULL);
    		printf("Fin du thread %ld\n",i);
    	}
    	pthread_join(Threads_t.Thread_Mere,NULL);
     
    	return EXIT_SUCCESS;
    }

  2. #2
    Membre éclairé Avatar de valefor
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    711
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 711
    Points : 790
    Points
    790
    Par défaut
    Nulle part tu bloques sur Cond_Die. Est-ce normal ? Cela ne sert à rien de broadcaster si personne n'attend.

    Un autre mécanisme de synchro sympa à utiliser (si ton implémentation des pthread le permet), c'est les "barrier" qui me semble apparenté à un point de rendez-vous (voir pthread_barrier_wait par exemple).

  3. #3
    Membre du Club
    Inscrit en
    Mai 2005
    Messages
    77
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 77
    Points : 58
    Points
    58
    Par défaut
    Salut
    Je n'ai pas utilisé le signal du broadcast, car je ne vois pas où le mettre au niveau des threads fils. En fait je ne vois pas comment faire un "ou" avec le cond_wait... si toutefois il s'agit d'un "ou".
    Je vais regarder les "barrier" en attendant !
    Merci
    Iza

  4. #4
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    25
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Mars 2008
    Messages : 25
    Points : 29
    Points
    29
    Par défaut
    Il est possible aussi que tu es une situation de famine, ou interblocage...
    Regarde (ou montre-nous) une trace d'exécution et essaye de faire tourner ton programme à la main (ouais, je sais, c'est barbare, mais ça a fait ses preuves) avec par exemple un thread mère et 2 ou 3 threads "exécutants", en imaginant différentes situations, notamment sur qui fait quoi et quand : rappelles-toi bien que ce sont des threads, et qu'on peut t'arrêter pratiquement n'importe où dans ton programme ;-)

  5. #5
    Membre du Club
    Inscrit en
    Mai 2005
    Messages
    77
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 77
    Points : 58
    Points
    58
    Par défaut
    Salut
    Je le fait tourner en mode debug, donc à la main. Le problème vient lorsque la tache mère se termine (car elle se termine avant les fils). Celle-ci lit une liste de commandes et les donne à exécuter quand les threads le demandent. Le thread envoie donc un signal, la tache mère lui donne une commande à exécuter, puis lui renvoie un signal pour lui dire de continuer. Quand il n'y a plus de commande, la tache mère envoie un signal de type broadcast, mais je ne sais pas comment le coder au niveau des threads.... Dans mon cas, j'en fait tourner 5. Quand il n'y a plus rien à exécuter, chacun attend le signal pour continuer les exécutions de commande, je ne sais comment comment coder le programme pour que suivant le signal envoyé, le thread se termine ou faisse quelque chose. Je ne sais pas si j'ai été très claire...
    Merci.
    Iza

  6. #6
    Membre éclairé Avatar de valefor
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    711
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 711
    Points : 790
    Points
    790
    Par défaut
    Attention, pthread_cond_broadcast ne permet pas de dire
    suivant le signal envoyé, le thread se termine ou fasse quelque chose
    .

    En fait cette fonction permet juste de dire qu'un truc s'est passé. Sur certaines pages de man y'a un exemple d'utilisation simple. Je ne pense pas que tu puisse différencier plusierus types de signaux.

Discussions similaires

  1. Réponses: 5
    Dernier message: 30/05/2005, 16h58

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo