Search code examples
cposixmutex

Thread rendez vous monitor


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:

sample

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

Solution

  • 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_RDVth, 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_RDVth 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.