I'm trying to implement a rendez vous with monitor and mutex, but it's not really working. I hope you can help me to see the issue. Here's the code:
void traitement_principal(){
if(iRdv==NB_RDV){
iRdv=0;
continuer=1;
pthread_cond_signal(&autoContinuer);
}else{
continuer=0;
}
while(continuer!=1){
pthread_cond_wait(&autoContinuer,&emAffichage);
}
printf("Thread %lu, je finis mon traitement mon traitement \n",pthread_self());
}
void* traitement(){
pthread_mutex_lock (&emAffichage);//demande accès
printf("Thread %lu, je commence mon traitement \n",pthread_self());
iRdv+=1;
traitement_principal();
pthread_mutex_unlock (&emAffichage);//rend accès
pthread_exit((void *)NULL);
}
void thdErreur(int codeErr, char *msgErr, void *codeArret) {
fprintf(stderr, "%s: %d soit %s \n", msgErr, codeErr, strerror(codeErr));
pthread_exit(codeArret);
}
int main(int argc, char const *argv[]){
int etat;
pthread_t idThd[NB_THREADS];
for(int i = 0; i < NB_THREADS; i++){
if ((etat = pthread_create(&idThd[i], NULL, traitement,NULL)) != 0)
thdErreur(etat, "Creation thread avec rdv",NULL);
}
for (int i = 0; i < NB_THREADS; i++)
if ((etat = pthread_join(idThd[i], NULL)) != 0)
thdErreur(etat, "Join threads afficheurs", NULL);
printf ("\nFin de l'execution du thread principal \n");
return 0;
}
NB_RDV
is a macro that expands to 3
.
iRDV
is a file-scope variable initialized to 0
.
continuer
is a file-scope variable initialized to 0
.
Here is an example of the program oputput:
It is not what I wanted. For example, for the first ones, I would like to get
Thread 0 I start
Thread 1 I start
Thread 2 I start
Thread 0 I end
Thread 1 I end
Thread 2 I end
The most significant problem in your code appears to be that traitement_principal()
calls pthread_cond_signal()
when the iRdv
counter reaches NB_RDV
. This will wake one thread waiting on the condition variable, but you need to wake multiple threads. To achieve that, you should call pthread_cond_broadcast()
instead.
But if you want to reliably wake exactly NB_RDV
threads and allow them to proceed, then you have a further problem. After the thread that broadcasts to the CV releases the mutex, you cannot be confident that the the just-woken threads will all re-acquire it before any other threads waiting on it acquire it. If a thread that was waiting in traitement()
acquires it first then that thread will enter traitement_principal()
and reset continuer
to 0
before the woken threads proceed, causing the latter to resume their wait when they eventually reacquire the mutex themselves.
If it's ok for any NB_RDV
threads to proceed past the barrier after that number have reached it -- maybe including threads that reach it after the NB_RDV
th, then you can achieve that with a few modifications. Instead of implementing continuer
as a flag, make it a counter whose value at any given time indicates how many more threads may proceed past the rendezvous without (further) waiting.
On the other hand, if you need to ensure that the first NB_RDV
th threads to arrive at the rendezvous are also the first to leave, then I think you'll need to add some form of shared state tracking their order of arrival.