Frage

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.

War es hilfreich?

Lösung

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".

Andere Tipps

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) {
}

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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top