寻找最佳的多线程消息队列

时间:2010-07-28 02:55:14

标签: multithreading message-queue messaging

我想在进程内运行多个线程。我正在寻找能够在线程之间传递消息的最有效方法。

每个线程都有一个共享内存输入消息缓冲区。其他线程会写入适当的缓冲区。

消息优先。我想自己管理这个过程。

没有昂贵的锁定或同步,最好的方法是什么?或者是否已经有一个久经考验的图书馆? (Delphi,C或C#很好)。

2 个答案:

答案 0 :(得分:2)

如果不重复其他人已经为你做出的许多错误,这很难做到:)

看一下Intel Threading Building Blocks - 图书馆有几个精心设计的队列模板(以及其他馆藏),您可以测试并找出最适合您的目的。

答案 1 :(得分: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继承私有。这可以防止在不通过我们的(同步)方法的情况下对队列进行原始访问。

将这样的队列分配给每个线程,您就在路上。

免责声明这里的代码被快速打了一下,以说明一点。在用于生产之前,它可能存在错误并需要检查和测试。