how to know which thread was released by pthread_cond_signal

164 views Asked by At

Cheers,

I have 2 threads causing logical deadlock => d_santa and d_patuljak (sorry some pieces are written in Croatian and I didn't have the time to translate)

d_santa does this

void d_santa(){ //dodati join!!!
    int j;
    pthread_mutex_lock(&m);
    while(1){
        pthread_cond_wait(&u_santa,&m);
        if ((br_sob==10)&&(br_patuljak)){
            printf ("Dajem poklone i rijesavam se sobova\n");
            pthread_cond_broadcast(&u_sob);
            sleep(2);
            for (j=2; j<=11; j++){
                printf ("Pokusavam brisat sob na %d\n",j);
                pthread_join(thred[j],NULL);
                br_sob--;
                printf ("broj sobova=%d\n",br_sob);
            }
        }
        if (br_sob==10){
            printf("Hrani nezahvalnu bagru\n");
            sleep(2);
        }
        if ((br_patuljak%3)==0){
            pthread_cond_broadcast(&u_patuljak);
            printf ("Rijesi problem patuljaka\n");
            sleep(1);               
            for (j=0; j<3; j++){
                br_ulaz++;
                printf("Oslobađam dretvu %d\n",H_ULAZ);
                pthread_join(thred[H_ULAZ],NULL);                                   
                br_patuljak--;
                }
        }
    }
    pthread_mutex_unlock(&m);
}

and d_patuljak does this

void d_patuljak(){ //zavrsi implementaciju proizvodac potrosac
    pthread_mutex_lock(&m);
    br_patuljak++;
    printf ("Nastao je patuljak %d\n",br_patuljak);
    while(br_patuljak<3){
        pthread_cond_wait(&u_patuljak,&m);
    }
    printf ("Patuljak se oslobodio\n");
    if (br_patuljak==3){
        pthread_cond_signal(&u_santa);
    }
    pthread_mutex_unlock(&m);
}

Here's also d_sob if it helps

void d_sob(){  //dobar
    int id; 
    pthread_mutex_lock(&m);
    id=br_sob+2;    
    br_sob++;
    printf ("Nastao je sob %d\n",br_sob);
    while(br_sob<10){
        pthread_cond_wait(&u_sob,&m);
    }
    pthread_cond_signal(&u_santa);
    printf ("Sob ceka slobodu %d, a za analizu br_sob=%d\n",id,br_sob); 
    pthread_mutex_unlock(&m);
}

The task: d_santa is created only once and always remains sleeping or doing something "useful" while d_patuljak keeps being created and when a group 3 is created they wake up santa so he could help them solve all their problems (note if d_patuljak is created fast there can be more than 3 patuljaks but santa takes only a group of 3!!). Similiar for sob they keep being created until they reach a number of 10 afterwards they can be broadcasted (there can't be 11 of them)

My solution (thoughts): I'll create 1,2,3 patuljaks each having their own location in an array. When patuljak 3 is created he will wake up santa (also bypass pthread_cond_wait)! Santa will wake up and call 3 consecutive pthread_cond_signals to release patuljak 1, patuljak 2 then patuljak 3 => note: patuljak 1 is released to end his thread then be 'destroyed' by pthread_join which I placed right below pthread_cond_signal!!

The problem: pthread_join(patuljak 1) keeps waiting for patuljak 1 which means pthread_cond_signal didn't manage to release patuljak 1 (perhaps patuljak 2 or 3)? I don't know a way to solve this problem is there a way of knowing what will be released or maybe how to release exactly patuljak 1,2,3? I'd use broadcast but I can't patuljak 4 will be released and santa should take only groups of 3. EDIT: I switched pthread_cond_signal with pthread_cond_broadcast for patuljaks the problem didn't go away.

Anyway the programme is hell bigger than this I have a similiar problem with raindeers(=sob) which I can and tried to broadcast but they also get stuck at pthread_join, I have a feeling if the problem with patuljaks is solved the same will follow for raindeers (patuljak=>dwarf) xd.

3

There are 3 answers

1
David Schwartz On BEST ANSWER

Two rules will resolve these kinds of problems:

  1. Only call pthread_cond_signal when any thread that might be waiting on the condition variable can do whatever it is that needs to get done. Otherwise, always call pthread_cond_broadcast. When in doubt, call pthread_cond_broadcast, as it is always safe.

  2. Always call pthread_cond_wait inside a loop that calls pthread_cond_wait again in the event of a spurious wakeup. You must design your code so that "extra" wakeups are harmless and threads just go back to sleep if they wake up when they "shouldn't".

0
yushulx On

If you want to know which thread released, a simple way is to print thread id for distinguishing. Refer to Pthread Creation and Termination

void *PrintHello(void *threadid)
{
   long tid;
   tid = (long)threadid;
   printf("Hello World! It's me, thread #%ld!\n", tid);
   pthread_exit(NULL);
}


int main (int argc, char *argv[])
{
   pthread_t threads[NUM_THREADS];
   int rc;
   long t;
   for(t=0; t<NUM_THREADS; t++){
      printf("In main: creating thread %ld\n", t);
      rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
      if (rc){
         printf("ERROR; return code from pthread_create() is %d\n", rc);
         exit(-1);
      }
   }

   /* Last thing that main() should do */
   pthread_exit(NULL);
}

So you can modify your thread function like

void d_santa(void *threadid) {
}
0
Spidey On

So the actual solution (by grandmaster jax) was:

d_patuljak

void d_patuljak(){ //zavrsi implementaciju proizvodac potrosac
    pthread_mutex_lock(&m);
    br_patuljak++;
    printf ("Nastao je patuljak %d\n",br_patuljak);
    if (br_patuljak==3)
    {
        pthread_cond_signal(&u_santa);
    }
    while(varijabla<=0)
    {
        pthread_cond_wait(&u_patuljak,&m);
    }
    varijabla--;
    printf ("SLOBODA\n");
    pthread_mutex_unlock(&m);
}

d_santa

void d_santa(){ //dodati join!!!
    int j;
    pthread_mutex_lock(&m);
    while(1){
        pthread_cond_wait(&u_santa,&m);
        if ((br_sob==10)&&(br_patuljak)){
            printf ("Dajem poklone i rijesavam se sobova\n");
            pthread_cond_broadcast(&u_sob);
            sleep(2);
            for (j=2; j<=11; j++){
                varijabla2++;               
            }
            br_sob=br_sob-10;
        }
        if (br_sob==10){
            printf("Hrani nezahvalnu bagru\n");
            sleep(2);
        }
        if (br_patuljak>=3){
            printf ("Rijesi problem patuljaka\n");              
            sleep(1);
            for (j=0; j<3; j++){
                varijabla++;
                pthread_cond_signal(&u_patuljak);                                   
            }
            br_patuljak=br_patuljak-3;
        }
    }
    pthread_mutex_unlock(&m);
}

The same solution can be applied to d_sob .... in short the problem was the condition in while(), the first thread would be free then reduce the counter which would lock other threads.