2009-09-10 93 views
0

我試圖在C中的多生產者/消費者問題,但它不按預期工作。以下是代表我的實現的一些僞代碼。多生產者/消費者和關鍵部分代碼問題

Thread thread1; 
Thread thread2; 
Thread thread3; 

Data data1; 
Mutex data1_mutex; 
Semaphore data1_empty; 
Semaphore data1_fill; 

Data data2; 
Mutex data2_mutex; 
Semaphore data2_empty; 
Semaphore data2_fill; 

thread1() 
{ 
    // creates data and places it into data1. 

    wait(data1_empty); 
    lock(data1_mutex); 

    // critical section 

    unlock(data1_mutex); 
    post(data1_fill); 
} 

thread2() 
{ 
    // Removes data from data1, processes it, and places it into data2. 

    // data1 
    wait(data1_fill); 
    lock(data1_mutex); 

    // data2 
    wait(data2_empty); 
    lock(data2_mutex); 

    // critical section 

    // data2 
    unlock(data2_mutex); 
    post(data2_fill); 

    // data1 
    unlock(data1_mutex); 
    post(data1_empty); 
} 

thread3() 
{ 
    // Removes data from data2, prints its results, and removes it. 

    wait(data2_fill); 
    lock(data2_mutex); 

    // critical section 

    unlock(data2_mutex); 
    post(data2_empty); 
} 

但是,使用此解決方案data1將填滿,但thread2將鎖定,永不運行。我的實現有什麼問題嗎?

編輯#1

一個我發現的問題是,我的第二個互斥體沒有被正確創建。我不知道它有什麼問題,所以我只是在所有線程中使用第一個互斥鎖。我還做了一些其他工作來讓它工作,所以我稍後會更新我的僞代碼,以便稍後反思。

回答

0

確保您最初發布data1_emptydata2_empty

+0

你的意思是線程紡前? – Nippysaurus 2009-09-10 23:37:09

+0

我不認爲這很重要。我的觀點是:你所顯示的代碼確實看起來像是正確的,只要條件變量是最初發布的。您也可以使用帶有線程的調試器並查看每個卡在哪裏。 – 2009-09-10 23:48:11

+0

我目前沒有IDE或調試器。我已經嘗試在旋轉線程之前發佈到兩個信號量,但它導致data1設置的值超過了它的空間,所以我不認爲這是一個解決方案? – Nippysaurus 2009-09-11 01:35:16

0

這是什麼爭吵說,並且在等待data_2_empty時儘量不要鎖住data_1。您可以通過爲換出的data_1和data_2保留一個備用緩衝區來實現此目的。線程2在將數據1處理成數據_2時交換數據_1,線程_3在處理數據_2時交換出數據_2。您當前的僞代碼將允許線程1和線程3同時運行,但它不會允許線程2與其他任何一個同時執行。

1

如果您對Data使用某種排隊類型,則應該能夠完全刪除「空」信號量,除非您試圖強制每個Data隊列深度嚴格爲0或1。使用thread2中的局部變量,可以減小臨界區域的大小。然後

的代碼變成這樣的:

thread1() { 
    //Wait for data to put in the queue (i.e. a blocking socket read) 
    lock(data1_mutex); 
    data1.push(someData); 
    unlock(data1_mutex); 
    post(data1_fill); 
} 

thread2() { 
    DataType dataElement; 
    wait(data1_fill); 
    lock(data1_mutex); 
    dataElement = data1.pop(); 
    unlock(data1_mutex); 

    lock(data2_mutex); 
    data2.push(dataElement); 
    unlock(data2_mutex); 
    post(data2_fill); 
} 

thread3() { 
    DataType dataElement; 
    wait(data2_fill); 
    lock(data2_mutex); 
    dataElement = data2.pop(); 
    unlock(data2_mutex); 
    //do something with dataElement here 
} 
+0

如果.pop()創建副本,則thread3可以在使用dataElement之前解鎖(data2_mutex)。如果它是通過ref,那麼thread2無法解鎖data1_mutex,直到它將dataElement複製到data2中。 (我認爲推送和流行不可能通過參考。) – 2009-12-08 19:21:39