2017-03-15 38 views
2

我正在學習關於多線程的,我想模擬生產者消費者問題(使用旗語如果我可以稱呼它)。段錯誤發生的歷史同步隊列

我有一個持有隊列,製片人推到整數隊列類和消費類檢索它並打印。我模擬是如下

class TestClass{ 
public: 
    void producer(int i){ 
     unique_lock<mutex> l(m); 
     q.push(i); 
     if(q.size()) 
      cnd.notify_all(); 
    } 

    void consumer(){ 
     unique_lock<mutex> l(m); 
     while(q.empty()){ 
      cnd.wait(l); 
     } 
     int tmp = q.front(); 
     q.pop(); 
     cout << "Producer got " << tmp << endl; 
    } 
    void ConsumerInit(int threads){ 
     for(int i = 0; i < threads; i++){ 
      thrs[i] = thread(&TestClass::consumer, this); 
     } 
     for(auto &a : thrs) 
      a.join(); 
    } 


private: 
    queue<int> q; 
    vector<thread> thrs; 
    mutex m; 
    condition_variable cnd; 
}; 

我使用的小控制檯應用程序來調用數據:

int main(){ 
    int x; 
    TestClass t; 
    int counter = 0; 
    while(cin >> x){ 
     if(x == 0) 
      break; 
     if(x == 1) 
      t.producer(counter++); 
     if(x == 2) 
      t.ConsumerInit(5); 
    } 
} 

因此,當用戶輸入1,數據被推入隊列中,如果用戶按2個線程是催生。

以任何順序調用它,例如,按下1 1然後2或2 1 1 它會拋出段錯誤。我不知道爲什麼我的我的代碼的理解如下:假設爲了2 1 1

我初始化5個線程,他們看到隊列爲空,所以他們去睡覺。當我向隊列中推送一個號碼時,它會通知所有睡眠的線程。 第一個喚醒再次鎖定互斥體,然後繼續從隊列中檢索數字,然後釋放互斥體,當互斥體釋放時,另一個線程完成相同的操作並解鎖互斥體,互斥體解鎖後的第三個線程仍處於循環狀態,請參閱該隊列再次爲空,並再次進入休眠狀態,與所有剩餘的線程一樣。

是這個邏輯是否正確?如果是這樣,爲什麼這樣的扔段錯誤,如果沒有,我感謝所有的解釋。

感謝您的幫助!

//編輯 通過回答suggets,我用vector.push_back替換了[],但是消費者現在對數據不做任何處理,不會接受或打印它。

+0

錯字,謝謝!更新它 – Darlyn

+0

哦,再次感謝:) – Darlyn

回答

1

你是不是擴大THRS載體,當你做

thrs[i] = thread(&CTest::consumer, this); 

你應該做

thrs.emplace_back(&CTest::consumer, this); 

這就是崩潰會。

+0

注意到了這一點,並添加的push_back,但消費者不做任何處理數據,現在,它不會把它和打印。如果沒有5個輸入等待(並且因此該程序不能做任何更多的輸入) – Darlyn

+0

ConsumerInit將無限期地阻塞。你在輸入「2 1 1」嗎? –

+0

用戶inpu是2 1 1,所以它創建線程,然後在隊列推數量的兩倍 – Darlyn

1

您的問題與多線程無關。您正在訪問std::vector出界外:

for (int i = 0; i < threads; i++) { 
     thrs[i] = thread(&CTest::consumer, this); 

    //... 
    vector<thread> thrs; 

thrs向量是空的,你要訪問,就好像它有條目。

要顯示的錯誤,使用:

 thrs.at(i) = thread(&CTest::consumer, this); 

,你將與std::out_of_range例外,而不是分割故障的歡迎。

+0

注意到了這一點,並添加的push_back,但消費者不做任何處理數據,現在,它不會把它和打印。 – Darlyn

+0

然後,這是另一個問題。 – PaulMcKenzie

1

如果輸入序列的格式不是1 1 1 1 1 ... 2,程序會死鎖。即如果該號碼,如果1s前述2小於五。

這裏的原因是:

如果隊列大小的總元素都小於5,主線程調用consumerInit,一些五個創建消費者線程將阻止等待接收隊列元素。同時,join操作中的主線程塊。由於主線程將等待消費者線程完成,而其中一些線程正在等待數據消耗,所以不會有任何進展。因此,僵局。

1

問題就在這裏:你進入2後等待消費者完成

for(auto &a : thrs) 
     a.join(); 

主線程被阻塞在這裏。因此,在此之後,您認爲您正在輸入輸入,而沒有cin發生。

刪除這兩條線,然後就可以進入1和生產者/消費者會做好自己的工作。