2010-07-28 85 views
1

我想在一個進程內運行多個線程。我正在尋找能夠在線程之間傳遞消息的最有效方式。尋找一個最佳的多線程消息隊列

每個線程都有一個共享內存輸入消息緩衝區。其他線程會寫入適當的緩衝區。

消息將具有優先權。我想自己管理這個過程。

沒有進入昂貴的鎖定或同步,最好的方法是什麼?或者是否已經有一個經過驗證的可用庫? (Delphi,C或C#很好)。

回答

2

這是很難得到正確不重複犯了很多錯誤已經爲你:)

由其他人看看Intel Threading Building Blocks - 庫中有幾個精心設計的隊列模板(和其他收藏品),您可以測試並查看哪個最適合您的目的。

+0

謝謝尼古拉:) – IamIC 2010-07-28 04:02:31

1

如果您要使用多個線程,很難避免同步。幸運的是它不是很難。

對於單個進程,臨界區通常是最佳選擇。這是快速和易於使用。爲了簡單起見,我通常將它包裝在一個類中以處理初始化和清理。

#include <Windows.h> 

class CTkCritSec 
{ 
public: 
    CTkCritSec(void) 
    { 
     ::InitializeCriticalSection(&m_critSec); 
    } 
    ~CTkCritSec(void) 
    { 
     ::DeleteCriticalSection(&m_critSec); 
    } 
    void Lock() 
    { 
     ::EnterCriticalSection(&m_critSec); 
    } 
    void Unlock() 
    { 
     ::LeaveCriticalSection(&m_critSec); 
    } 

private: 
    CRITICAL_SECTION m_critSec; 
}; 

使用鎖定/解鎖它的「自動鎖定」類可以使它更簡單。

class CTkAutoLock 
{ 
public: 
    CTkAutoLock(CTkCritSec &lock) 
    : m_lock(lock) 
    { 
     m_lock.Lock(); 
    } 
    virtual ~CTkAutoLock() 
    { 
     m_lock.Unlock(); 
    } 
private: 
    CTkCritSec &m_lock; 
}; 

任何你想鎖定的東西,實例化一個自動鎖定。當功能結束時,它將解鎖。此外,如果有例外,它會自動解鎖(提供異常安全)。

現在你可以做一個簡單的消息隊列進行性病優先級隊列

#include <queue> 
#include <deque> 
#include <functional> 
#include <string> 

struct CMsg 
{ 
    CMsg(const std::string &s, int n=1) 
    : sText(s), nPriority(n) 
    { 
    } 
    int   nPriority; 
    std::string sText; 

    struct Compare : public std::binary_function<bool, const CMsg *, const CMsg *> 
    { 
     bool operator() (const CMsg *p0, const CMsg *p1) 
     { 
      return p0->nPriority < p1->nPriority; 
     } 
    }; 
}; 

class CMsgQueue : 
     private std::priority_queue<CMsg *, std::deque<CMsg *>, CMsg::Compare > 
{ 
public: 
    void Push(CMsg *pJob) 
    { 
     CTkAutoLock lk(m_critSec); 
     push(pJob); 
    } 
    CMsg *Pop() 
    { 
     CTkAutoLock lk(m_critSec); 

     CMsg *pJob(NULL); 
     if (!Empty()) 
     { 
      pJob = top(); 
      pop(); 
     } 
     return pJob; 
    } 
    bool Empty() 
    { 
     CTkAutoLock lk(m_critSec); 

     return empty(); 
    } 

private: 
    CTkCritSec m_critSec; 
}; 

的CMSG的內容可以是你喜歡的東西。請注意,CMsgQue從std :: priority_queue繼承私有。這會阻止原始訪問隊列,而不通過我們的(同步)方法。

爲每個線程分配一個這樣的隊列,你就在路上。

免責聲明這裏的代碼被快速打包在一起來說明一個觀點。它可能存在錯誤,需要在用於生產之前進行審查和測試。

+0

謝謝邁克爾! 我看到了一個使用ASM的解決方案,可以抵消任何鎖的需求!我不認爲這在.Net中是可能的。 – IamIC 2010-07-28 15:59:21

+0

@IanC我不明白你怎麼能沒有鎖。我猜想ASM代碼本身就是在執行鎖。如果兩個線程同時嘗試訪問隊列,而沒有鎖定,則會發生不好的事情。 :-(你可以使用Interlocked *()函數來完成自己的鎖定,但通常這並不比使用關鍵部分容易。 – 2010-07-28 16:47:05

+0

我注意到在我的機器上,我可以每秒鎖定和解鎖200萬次。但是使用原子ASM函數,我可以每秒執行超過2000萬次鎖定/解鎖(使用cmpxchg),所以這兩種方法之間必須有顯着的差異。 – IamIC 2010-08-02 15:08:36