2012-12-02 15 views
9

我試圖爲2個線程實現pthread_cond_wait。我的測試代碼試圖用兩個線程瓶坯以下情形:2線程的pthread_cond_wait

  • 線程B等待條件
  • 線程A打印「Hello」五次
  • 線程A信號線程B
  • 線程A等待
  • 線程B打印 「再見」
  • 線程B信號線程A
  • 迴路,開始(X5)

到目前爲止,代碼打印出「Hello」五次然後卡住了。從例子我看似乎我是在正確的軌道上「鎖定互斥,等待,得到由另一個線程發出信號,解除互斥體,做的東西,循環」

測試代碼:

//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); 
} 

一個指針在正確的方向將不勝感激,謝謝! (在Linux上使用「gcc timeTest.c -o timeTest -lpthread」編譯的代碼)

+0

不,這是不需要的,我主要是嘗試變化,但正如你所說,這將是理想的只使用一個 –

回答

28

你有兩個問題。第一個是你沒有正確使用while()循環 - 例如,在這裏:

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

i++; 

while循環體是語句i++ - 這將執行pthread_cond_wait()i++直到pthread_cond_wait()返回一個錯誤,所以這本質上是一個無限循環。

第二個是你不能自己使用一個pthreads條件變量 - 它需要與一些實際的共享狀態配對(最簡單的,這個共享狀態可能只是一個被互斥鎖保護的標誌變量) 。 pthread_cond_wait()函數用於等待共享狀態達到某個值,當線程更改共享狀態時使用pthread_cond_signal()函數。返工您的示例使用了這樣的變量:

//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; 
} 

需要注意的是使用兩個條件變量condAcondB是不必要在這裏 - 如果使用的條件只有一個變量,而不是代碼將是一樣正確。

+4

啊,與while循環令人尷尬的錯誤!感謝關於使用共享狀態的輸入,我理解其使用背後的原因。關於單個條件變量的使用,我完全同意你的意思。非常感謝您的回覆,爲編寫較大的項目編寫代碼,再次感謝您的詳細回覆! –

+1

1所述共享狀態的很好的描述(通常稱爲「謂詞」),該CVAR-MTX對被設計來管理。 – WhozCraig

0

代碼實際上工作差不多當我在你的機器上添加大括號到while循環時。

添加到caf所說的,當threadA在已經發送condB信號之後啓動threadB時,您將進入無限循環,因此您需要在while循環中使用共享狀態。

您可以在第47行中引入使用usleep(1)的人工延遲,然後親自查看。

相關問題