2013-04-21 29 views
1

我學習我的方式,通過與C++ 11的同步原語我必須寫一個模板類,這是那些方法在施工時聲明最大元素數的FIFO隊列。在一個簡單的C++ 11四線程程序時,我的兩個消費者線程沒有返回,如果我的評論標準輸出打印線

有兩個線程這推動項目到所說的隊列中,另兩種檢索。它們通過使用兩個條件變量進行同步,以確保消費者線程僅在隊列不爲空時彈出項目,並且生產者線程僅在隊列未滿時才推送新項目。該隊列已獲得打開/關閉狀態,該狀態在條件變量的wait()調用中用作附加條件。當隊列關閉時,線程應該返回而不執行任何操作。

// main.cpp 
#include "stdafx.h" 

int _tmain(int argc, _TCHAR* argv[]){ 
    BlockingQueue<int> bq(10); 
    int sum1=0, sum2=0; 

    std::thread c1([&bq,&sum1](){ 
     int i; 
     while(bq.get(i)) sum1+=i; 
    }); 
    std::thread c2([&bq,&sum2](){ 
     int i; 
     while(bq.get(i)) sum2+=i; 
    }); 
    std::thread p1([&bq](){ 
    for(int i=0;i<1000;i+=2) bq.put(i); 
    }); 
    std::thread p2([&bq](){ 
    for(int i=0;i<1000;i+=2) bq.put(i+1); 
    }); 
    p1.join(); 
    std::cout<<"p1 thread returned."<<std::endl; 
    p2.join(); 
    std::cout<<"p2 thread returned."<<std::endl; 
    bq.close(); 
    c1.join(); 
    std::cout<<"c1 thread returned."<<std::endl; 
    c2.join(); 
    std::cout<<"c2 thread returned."<<std::endl; 
    std::cout<<"sum1: "<<sum1<<std::endl; 
    std::cout<<"sum2: "<<sum2<<std::endl; 
    std::cout<<"total: "<<sum1+sum2<<std::endl; 
    return 0; 
} 

下面是我創建的類:

// BlockingQueue.h 
#include "stdafx.h" 

template<class T> class BlockingQueue 
{ 
    std::mutex t_queue_mutex; 
    std::queue<T> t_queue; 
    int t_queue_cap_value; 
    bool isQueueOpen; 
    std::condition_variable put_condition; 
    std::condition_variable get_condition; 
public: 
    BlockingQueue(int N); 
    ~BlockingQueue(void); 
    bool put(T t_item); 
    bool get(T &t_item); 
    bool isOpen(); 
    bool isFull(); 
    bool isEmpty(); 
    void close(); 
}; 

// BlockinQueue.cpp 
#include "BlockingQueue.h" 
#include "stdafx.h" 

template <class T> BlockingQueue<T>::BlockingQueue(int N) 
{ 
    t_queue_cap_value=N; 
    isQueueOpen=true; 
    std::cout<<"Rejoice! A bq has been created!"<<std::endl; 
} 

template <class T> BlockingQueue<T>::~BlockingQueue(void) 
{ 
} 

template <class T> bool BlockingQueue<T>::isFull(){ 
    if(t_queue_cap_value==t_queue.size()) 
     return true; 
    else 
     return false; 
} 

template <class T> bool BlockingQueue<T>::isOpen(){ 
    return isQueueOpen; 
} 

template <class T> void BlockingQueue<T>::close(){ 
    isQueueOpen=false; 
} 

/* get method */ 
template <class T> bool BlockingQueue<T>::get(T &t_item){ 
    bool exitThreadStatus=false; 

    if(!isOpen()){ 
     put_condition.notify_all(); 
     return false; 
    } 
    std::unique_lock<std::mutex> ul(t_queue_mutex); 
    get_condition.wait(ul, [this](){ 
     //std::cout<<"Getter thread with get_id()="<<std::this_thread::get_id()<<" is waiting. isOpen()="<<isOpen()<<" and t_queue.empty()="<<t_queue.empty()<<std::endl; 
     if(!isOpen()) 
      return true; 
     else 
      return !t_queue.empty(); 
    }); 
    if(isOpen()){ 
     exitThreadStatus=true; 
     t_item=t_queue.front(); 
     t_queue.pop(); 
    } 
    std::cout<<"Extracted "<<t_item<<". After pop size()="<<t_queue.size()<<std::endl; 
    put_condition.notify_all(); 
    return exitThreadStatus; 
} 

/* put method */ 
template <class T> bool BlockingQueue<T>::put(T t_item){ 
    bool exitThreadStatus=false; 

    if(!isOpen()){ 
     get_condition.notify_all(); 
     return false; 
    } 
    std::unique_lock<std::mutex> ul(t_queue_mutex); 
    put_condition.wait(ul, [this](){ 
     if(!isOpen()) 
      return true; 
     else 
      return !isFull(); 
    }); 
     if(isOpen()){ 
     exitThreadStatus=true; 
     t_queue.push(t_item); 
    } 
    std::cout<<"Inserting "<<t_item<<". After push size()="<<t_queue.size()<<std::endl; 
    get_condition.notify_all(); 
    return exitThreadStatus; 
} 

template class BlockingQueue<int>; 

這似乎是正常工作,每當我離開的get(兩個性病::法院線)和put()註釋掉,得到下面的輸出(如預期):

Inserting 998. After push size()=2 
Extracted 997. After pop size()=1 
p1 thread returned. 
Inserting 999. After push size()=2 
Extracted 998. After pop size()=1 
p2 thread returned. 
Extracted 999. After pop size()=0 
Extracted 998. After pop size()=0 
c1 thread returned. 
c2 thread returned. 
sum1: 250000 
sum2: 249500 
total: 499500 

如果我不是評論的COUT線,兩線收集似乎永遠回來,我不明白什麼是錯我的代碼。有人有線索嗎?謝謝!

輸出帶有註釋COUT行:

Rejoice! A bq has been created! 
p1 thread returned. 
p2 thread returned. 

回答

3

嘗試增加get_condition.notify_all()和put_condition.notify_all()關閉()。

至於我可以告訴大家,如果一個線程在get_condition.wait()內的get()close()時被調用,它停留在永遠等待。爲什麼這與我不知道的cout陳述一起工作,儘管文檔確實提到了「虛假喚醒」。

+0

這一工程!非常感謝。通過使用喚醒條件作爲傳遞給條件變量wake()調用的lambda表達式形式的第二個參數來處理虛假喚醒。 – wallen 2013-04-21 17:04:17

相關問題