2012-12-02 5 views
9

Sto provando a implementare pthread_cond_wait per 2 thread. Il mio codice di prova sta cercando di utilizzare due thread per preforme il seguente scenario:pthread_cond_wait per 2 thread

  • attese thread B per la condizione
  • discussione stampe un "ciao" cinque volte
  • Discussione Un filo segnali B
  • Discussione A attende
  • stampe thread B "arrivederci"
  • segnali
  • thread B infilare un
  • loop per iniziare (x5)

Finora il codice stampa "Ciao" cinque volte e poi si blocca. Da esempi che ho guardato a quanto pare io sono sulla strada giusta, "Blocco mutex, aspettare, Get segnalato da un altro thread, mutex sbloccare, fare cose, loop"

Codice di prova:

//Import 
#include <stdio.h> 
#include <stdlib.h> 
#include <pthread.h> 
#include <unistd.h> 

//global variables 
pthread_cond_t  condA = PTHREAD_COND_INITIALIZER; 
pthread_cond_t  condB = PTHREAD_COND_INITIALIZER; 
pthread_mutex_t  mutex = PTHREAD_MUTEX_INITIALIZER; 




void *threadA() 
{ 
    int i = 0, rValue, loopNum; 

    while(i<5) 
    { 
     //unlock mutex 
     rValue = pthread_mutex_unlock(&mutex); 

     //do stuff 
     for(loopNum = 1; loopNum <= 5; loopNum++) 
      printf("Hello %d\n", loopNum); 

     //signal condition of thread b 
     rValue = pthread_cond_signal(&condB); 

     //lock mutex 
     rValue = pthread_mutex_lock(&mutex); 

     //wait for turn 
     while(pthread_cond_wait(&condA, &mutex) != 0) 

     i++; 
    } 

} 



void *threadB() 
{ 
    int n = 0, rValue; 

    while(n<5) 
    { 
     //lock mutex 
     rValue = pthread_mutex_lock(&mutex); 

     //wait for turn 
     while(pthread_cond_wait(&condB, &mutex) != 0) 

     //unlock mutex 
     rValue = pthread_mutex_unlock(&mutex); 

     //do stuff 
     printf("Goodbye"); 

     //signal condition a 
     rValue = pthread_cond_signal(&condA); 

     n++;   
    } 
} 




int main(int argc, char *argv[]) 
{ 
    //create our threads 
    pthread_t a, b; 

    pthread_create(&a, NULL, threadA, NULL); 
    pthread_create(&b, NULL, threadB, NULL); 

    pthread_join(a, NULL); 
    pthread_join(b,NULL); 
} 

Un puntatore nella giusta direzione sarebbe molto apprezzato, grazie! (Codice compilato su Linux utilizzando "gcc timeTest.c -o timeTest -lpthread")

+0

No, non è necessario, stavo provando principalmente variazioni ma come hai detto sarebbe ideale usare solo uno –

risposta

28

Hai due problemi. La prima è che non si sta utilizzando while() loop correttamente - ad esempio, qui:

//wait for turn 
while(pthread_cond_wait(&condA, &mutex) != 0) 

i++; 

Il corpo del ciclo while è la dichiarazione i++ - questo eseguirà pthread_cond_wait() e i++ fino alla pthread_cond_wait() restituisce un errore, così questo è essenzialmente un ciclo infinito.

Il secondo è che non è possibile utilizzare una variabile di condizione pthreads da sola: deve essere abbinata a uno stato condiviso effettivo (nel modo più semplice, questo stato condiviso potrebbe essere semplicemente una variabile di flag protetta da un mutex) . La funzione pthread_cond_wait() viene utilizzata per attendere che lo stato condiviso raggiunga un determinato valore e la funzione pthread_cond_signal() viene utilizzata quando un thread ha modificato lo stato condiviso. Rielaborare il tuo esempio di utilizzare una tale variabile:

//global variables 
/* STATE_A = THREAD A runs next, STATE_B = THREAD B runs next */ 
enum { STATE_A, STATE_B } state = STATE_A; 
pthread_cond_t  condA = PTHREAD_COND_INITIALIZER; 
pthread_cond_t  condB = PTHREAD_COND_INITIALIZER; 
pthread_mutex_t  mutex = PTHREAD_MUTEX_INITIALIZER; 

void *threadA() 
{ 
    int i = 0, rValue, loopNum; 

    while(i<5) 
    { 
     /* Wait for state A */ 
     pthread_mutex_lock(&mutex); 
     while (state != STATE_A) 
      pthread_cond_wait(&condA, &mutex); 
     pthread_mutex_unlock(&mutex); 

     //do stuff 
     for(loopNum = 1; loopNum <= 5; loopNum++) 
      printf("Hello %d\n", loopNum); 

     /* Set state to B and wake up thread B */ 
     pthread_mutex_lock(&mutex); 
     state = STATE_B; 
     pthread_cond_signal(&condB); 
     pthread_mutex_unlock(&mutex); 

     i++; 
    } 

    return 0; 
} 

void *threadB() 
{ 
    int n = 0, rValue; 

    while(n<5) 
    { 
     /* Wait for state B */ 
     pthread_mutex_lock(&mutex); 
     while (state != STATE_B) 
      pthread_cond_wait(&condB, &mutex); 
     pthread_mutex_unlock(&mutex); 

     //do stuff 
     printf("Goodbye\n"); 

     /* Set state to A and wake up thread A */ 
     pthread_mutex_lock(&mutex); 
     state = STATE_A; 
     pthread_cond_signal(&condA); 
     pthread_mutex_unlock(&mutex); 

     n++; 
    } 

    return 0; 
} 

Si noti che l'uso di due variabili di condizione condA e condB è inutile qui - il codice sarebbe altrettanto corretto se solo una variabile di condizione è stato usato al posto.

+4

Ah, errore imbarazzante con il ciclo while! Grazie per l'input sull'utilizzo degli stati condivisi, capisco il ragionamento dietro il suo utilizzo.Per quanto riguarda l'uso di una singola variabile di condizione, sono completamente d'accordo con quello che stai dicendo. Grazie mille per la risposta, tempo per codificare il progetto più grande, grazie ancora per la risposta dettagliata! –

+1

+1 bella descrizione dello stato condiviso (spesso chiamato 'predicato') che le coppie di cvar-mtx sono progettate per gestire. – WhozCraig

0

Il codice funziona effettivamente quasi correttamente sulla mia macchina quando si aggiungono parentesi graffe al ciclo while.

In aggiunta a quanto detto da caf, si entra in un ciclo infinito quando threadB viene avviato dopo che threadA ha già inviato il segnale condB, quindi perché è necessario utilizzare uno stato condiviso nel proprio ciclo while.

È possibile introdurre un ritardo artificiale utilizzando usleep(1) sulla riga 47 e vedere di persona.