2013-03-21 70 views
0

我在C++和我的主線程中編寫多線程程序我正在等待其他線程將程序包放入不同的隊列。取決於包的種類以及它們來自哪個線程。C++ std條件變量覆蓋很多共享變量

隊列受互斥體保護,因爲它應該是。

但在我主我不想做:

while(true) 
if(!queue1->empty) 
{ 
    do stuff 
} 
if(!queue2->empty) 
{ 
    do stuff 
} 
etc 

所以你需要使用條件變量信號的主要事情有了變化。現在我只能阻塞1個條件變量,所以我需要所有這些線程使用相同的條件變量和伴隨的互斥。現在我不想真正使用這個互斥鎖來鎖定我所有的線程。這並不意味着當1個線程寫入隊列時,另一個線程不能寫入完全不同的隊列。所以我爲每個隊列使用單獨的互斥體。但是現在我該如何使用條件變量附帶的這個額外的互斥鎖。

它是如何完成2線程和1隊列使用提升,非常類似於標準。 http://www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html

template<typename Data> 
class concurrent_queue 
{ 
    private: 
    boost::condition_variable the_condition_variable; 
    public: 
    void wait_for_data() 
    { 
     boost::mutex::scoped_lock lock(the_mutex); 
     while(the_queue.empty()) 
     { 
      the_condition_variable.wait(lock); 
     } 
    } 
    void push(Data const& data) 
    { 
     boost::mutex::scoped_lock lock(the_mutex); 
     bool const was_empty=the_queue.empty(); 
     the_queue.push(data); 
     if(was_empty) 
     { 
      the_condition_variable.notify_one(); 
     } 
    } 
    // rest as before 
}; 

那麼,你如何解決這個問題?

回答

3

我想說的關鍵是你的問題是在這裏:

Now I dont want to really use this mutex to lock all my threads. It doesn't mean that when 1 thread is writing to a queue, another cant write to a totally different queue. So I use seperate mutexes for each queue.

爲什麼?因爲:

... packages come in relatively slow. And queues are empty most of the time

在我看來,你已經設計成自己的,因爲你以爲你在需要的時候在現實中,你可能並不需要它,因爲一個隊列會在有實際工作的東西角落你提到的使用場景。

我想說從一個隊列開始,看看它有多遠讓你。然後,當你碰到一個限制,你確實有很多線程正在等待一個互斥鎖時,你將獲得更多關於這個問題的信息,因此能夠更好地解決這個問題。

實質上,我想說你面臨這個問題的原因是過早的設計優化,而解決這個問題的方法就是現在回溯和改變設計。

+0

一個隊列的問題是程序包是不同類的對象。根據它們在不同線程中產生的類型,還需要在主線程中進行不同的處理。也主要製作包並將它們發送到線程。我正在通過串口與Zigbee通信。我有一個web服務運行,它接受HTTP包,並且我是一個web服務的客戶端,它運行某種特殊的數據庫,並將數據放入其中。 所以1隊列不會工作,導致來自不同類別的數據包或對象。我不想整個演出。 (或者我應該怎麼做?) – Silver 2013-03-22 13:41:22

+1

您可以將該類型編碼爲數字字段,這將消除鑄造問題。 – Carl 2013-03-22 21:34:22

+0

Idd我可以做到這一點,但我並不覺得這樣做完全舒服。如果不是必要的話,一般的經驗法則不會過多。但我想在這種情況下可能有必要。 – Silver 2013-03-24 13:41:04

2

爲所有在其中工作的隊列創建一個頂級(可能是循環的)隊列。

這個隊列可以被一個互斥鎖保護,並且有一個condvar,當它從空變爲非空時,只需要發信號。

現在,您的個人隊列可以每個人都有自己的互斥,而他們只需要觸摸共享/頂級隊列(和它的互斥體)時他們改變從空非空。

一些細節將取決於您是希望您的線程依次從每個非空隊列中依次獲取前端項目,還是依次佔用每個整個隊列,但這個想法就在那裏。


從非空要非空(但增加的大小)也應傳遞到頂級隊列?

如我所說,這取決於你如何消費它們。如果,每次一個隊列有東西在裏面,你這樣做:

  1. (你已經擁有了頂級的鎖,那你怎麼知道這個隊列中有東西在裏面)
  2. 鎖定隊列
  3. 交換與本地工作副本
  4. 隊列內容從頂層隊列
  5. 解鎖隊列除去隊列

則工作隊列總是或者是非空,因此在頂層隊列中,爲空,因此不在隊列中。

如果你不要做到這一點,只要關閉每個非空隊列的前端元素,那麼你有更多的狀態要考慮。


注意,如果

...包進來相對較慢。和隊列爲空的大部分時間

你很可能只是擁有一個隊列,因爲不會有足夠的活動引起了很多爭論。這極大地簡化了事情。

+0

好的軟件包進來相對較慢。大部分時間隊列都是空的。所以每次包進來時,我仍然需要訪問頂層隊列。 此外,我不明白爲什麼只有當單個隊列從空到非空時才能鎖定頂層隊列。從非空到非空(但增加大小)也應該傳遞到頂層隊列? 我想我可能會將共享隊列中的項目複製到我的主隊列中的本地隊列中。因爲處理可能需要一些地方。所以清空隊列將會相對較快。只需要queue.front()和queue.pop()。 – Silver 2013-03-21 22:32:23

+0

鎖定所有隊列不會讓我的程序很糟糕,但它是論文的一部分,我想盡可能優化它。我可以只使用一個互斥體來鎖定並用於我的條件變量,但不會鎖定任何隊列。或者你認爲這會在某個地方造成問題嗎? – Silver 2013-03-21 22:37:13

0

@Carleeto和@Useless都給出了很好的答案。你只有一個消費者,所以一個隊列會給你最好的性能。無法獲得比單個消費者持續工作更高的吞吐量,因此您的目標應該是儘量減少單個消費者的鎖定開銷,而不是生產者。您可以通過讓生產者用單個互斥鎖等待單個條件變量(指示該隊列非空)來完成此操作。

下面是你如何做參數多態性。完整的類型安全性,不需要鑄造,並且在父類中只有一個虛函數:

class ParentType { 
public: 
    virtual void do_work(...[params]...)=0; 
    virtual ~ParentType() {} 
}; 

class ChildType1 : public ParentType { 
private: 
    // all my private variables and functions 
public: 
    virtual void do_work(...[params]...) { 
    // call private functions and use private variables from ChildType1 
    } 
}; 

class ChildType2: public ParentType { 
private: 
    // completely different private variables and functions 
public: 
    virtual void do-work(...[params]...) { 
    // call private functions and use private variables from ChildType2 
    } 
};