2010-11-05 73 views
2

我正嘗試在有界緩衝區中使用生產者/消費者線程。緩衝區的長度是5.我有1個互斥體和2個信號量,它們是以緩衝區的大小開始的空的,並且是滿的,從0開始。C - 生產者/消費者死鎖問題

當我在末尾沒有運行sleep() ,它會不斷產生,直到緩衝區是完全充分的消耗,直到它是空的,所以輸出如下所示:

Placed 1 in the buffer at position 0. 
Placed 2 in the buffer at position 1. 
Placed 3 in the buffer at position 2. 
Placed 4 in the buffer at position 3. 
Placed 5 in the buffer at position 4. 
The buffer now contains 0 at position 0. 
The buffer now contains 0 at position 1. 
The buffer now contains 0 at position 2. 
The buffer now contains 0 at position 3. 
The buffer now contains 0 at position 4. 

然而,當我在最後的睡眠()運行時,它打印出:

Placed 1 in the buffer at position 0. 
The buffer now contains 0 at position 0. 

然後它似乎鎖定,但我不確定它爲什麼表現wa無論睡眠是否存在,它都會這樣做。有什麼建議麼?我的主要方法基本上只是做一些聲明,然後創建1個線程產生和1消耗,這些方法在下面。

void *producer() 
{ 
     int k = 0; //producer index 
     while (1) 
     { 
       sem_wait(&empty); 
       pthread_mutex_lock(&mutex); 
       buffer[k] = k+1; 
       sem_post(&full); 
       pthread_mutex_unlock(&mutex); 
       printf("Placed %d in the buffer at position %d.\n", buffer[k], k); 
       k = (k + 1) % BUFFER_SIZE; 
       sleep(rand() * 10); 
     } 
} 

void *consumer() 
{ 
     int j = 0; //consumer index 
     while(1) 
     { 
       sem_wait(&full); 
       pthread_mutex_lock(&mutex); 
       buffer[j] = 0; 
       sem_post(&empty); 
       pthread_mutex_unlock(&mutex); 
       printf("The buffer now contains %d at position %d.\n", buffer[j], j); 
       j = (j + 1) % BUFFER_SIZE; 
       sleep(rand() * 10); 

     } 
} 
+0

我建議你丟掉你的代碼,並用僞代碼重寫任務。或者你可能再次用C重寫它,這通常會幫助我找到這樣的難題。 – 2010-11-05 19:15:30

+0

我可以看到一個(無關的)問題,消費者指數j應由消費者共享。如果它對每個線程都是本地的,它並沒有幫助。讓'j'全球化。 – 2010-11-05 19:16:46

+0

謝謝,我實際上正在計劃在實現多線程時這樣做,但現在我只有1個生產者和1個消費者。 – john 2010-11-05 19:19:23

回答

3

參數sleep()是睡眠秒數。 rand()會返回一個介於0和RAND_MAX之間的整數(通常爲32767或2 -1),當您將其乘以10時,您會在荒謬的大量時間內睡覺。你並沒有陷入僵局,只是睡了很長時間。

+0

嗯,出於某種原因,我認爲rand()在0和1之間。謝謝,我會試着調整它。 – john 2010-11-05 19:21:27

+0

工作,謝謝。你有什麼想法,爲什麼當我不包括睡眠,它總是生產和消費塊,而不是其他所有? – john 2010-11-05 19:32:07

+0

@john如果你不強制任何東西,你通常會得到最有效的結果。 – 2016-07-11 07:03:11

2

我不知道這是否是您僵局的原因,但你必須要小心sem_t功能,它們受到中斷,特別是由於IO之類的東西。

切勿忽略系統功能的返回。在這裏,你必須檢查退貨,然後errnoEINTR

然後,我不知道你是否被迫使用sem_t,但我認爲更自然的是使用pthread_cond_t。無論如何你都有一個互斥體,所以這會更容易。 pthread_cond_t作爲pthread_mutex_t函數將永遠不會中斷。

0

我假設你的兩個線程具有相同的優先級?這是在多核心的機器上,還是隻有一個?只是發出一個信號燈的信號不會搶佔當前的線程,因此預計當前線程將繼續運行,直到其片段到期。

此外,我會在發出互斥信號之前解鎖互斥鎖。

+0

我正在使用的機器是雙核心。如果消費者線程同時運行,不斷檢查可以開始消費的條件,並且生產者線程在1次生產後發出信號量,那麼消費者不應該在生產者運行一次後開始運行嗎? – john 2010-11-05 19:39:16

+0

它應該。順便說一句,什麼是互斥體?由於您在寫完信號後發出信號(如您應該那樣),因此您絕對不要寫入消費者線程正在讀取的地址。 – EboMike 2010-11-05 19:41:19

+0

好吧,我查看的很多代碼都使用它,並且在本實驗中,我認爲我應該將訪問緩衝區視爲關鍵部分。如果我有多個消費者和生產者,我不需要互斥體呢? – john 2010-11-05 19:48:16

1

Do you have any idea why when I don't include sleep it always produces and consumes in blocks instead of every other?

那可能是因爲〜30 ms的時間片的每個線程都有較足有生產者的產品包羅萬象,上下文切換必須發生的機會以前多了。