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

Multithreading 寻找最佳的多线程消息队列,multithreading,message-queue,messaging,Multithreading,Message Queue,Messaging,我想在一个进程中运行几个线程。我正在寻找能够在线程之间传递消息的最有效的方法 每个线程都有一个共享内存输入消息缓冲区。其他线程将写入适当的缓冲区 信息将具有优先权。我想自己管理这个过程 如果不进行昂贵的锁定或同步,最好的方法是什么?或者已经有一个行之有效的库可用于此?(德尔菲法、C法或C法都可以)。如果不重复别人已经为你犯过的许多错误,就很难纠正这一点:) 请看一看-库中有几个精心设计的队列模板(和其他集合),您可以测试并查看哪个最适合您的目的。如果要使用多个线程,很难避免同步。幸运的是,这并不

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

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

信息将具有优先权。我想自己管理这个过程


如果不进行昂贵的锁定或同步,最好的方法是什么?或者已经有一个行之有效的库可用于此?(德尔菲法、C法或C法都可以)。

如果不重复别人已经为你犯过的许多错误,就很难纠正这一点:)


请看一看-库中有几个精心设计的队列模板(和其他集合),您可以测试并查看哪个最适合您的目的。

如果要使用多个线程,很难避免同步。幸运的是,这并不难

对于单个流程,关键部分通常是最佳选择。它是快速和易于使用。为了简单起见,我通常将其包装在一个类中以处理初始化和清理

#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;
};
无论你想锁定什么东西,实例化一个自动锁定。当功能完成时,它将解锁。此外,如果出现异常,它将自动解锁(提供异常安全性)

现在,您可以从std优先级队列中生成一个简单的消息队列

#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
{
CMsg(常数std::string&s,int n=1)
:sText(s),nPriority(n)
{
}
内在优势;
std::string-sText;
结构比较:公共标准::二进制函数
{
布尔运算符()(常数CMsg*p0,常数CMsg*p1)
{ 
返回p0->NPRORITYNPRORITY;
}
};
};
类别CMsgQueue:
私有std::优先级队列
{
公众:
无效推送(CMsg*pJob)
{
CTkAutoLock lk(m_critSec);
推(pJob);
}
CMsg*Pop()
{
CTkAutoLock lk(m_critSec);
CMsg*pJob(空);
如果(!Empty())
{
pJob=top();
pop();
}
返回工作;
}
bool Empty()
{
CTkAutoLock lk(m_critSec);
返回空();
}
私人:
CTkCritSec m_critSec;
};
CMsg的内容可以是您喜欢的任何内容。请注意,CMsgQue从std::priority_队列私下继承。这可以防止在不经过我们的(同步)方法的情况下对队列进行原始访问

将这样的队列分配给每个线程,您就可以开始了


免责声明此处的代码被快速拼凑起来以说明一点。它可能有错误,在用于生产之前需要检查和测试。

谢谢Michael!我看到了一个使用ASM的解决方案,它不需要任何锁!我认为这在.Net中是不可能的。@IanC我不知道没有锁怎么做。我猜ASM代码是自己锁的。如果两个线程试图在没有锁的情况下同时访问队列,则会发生不好的事情:-(您可以使用联锁*()功能进行自己的锁定,但一般来说,这并不比使用关键部分简单。我注意到,在我的机器上,我每秒可以锁定和解锁200万次。但使用原子ASM功能,我可以每秒执行2000多万次锁定/解锁(使用cmpxchg)。因此,这两种方法之间肯定有很大的区别。@IanC--这取决于事务其余部分的速度。如果锁定占事务时间的10%,而您将其减少到0.01%,这可能非常有用。如果锁定占事务时间的0.001%,而您将其减少到0.00001%,则没有人会在意。ASM通常会更快,但它可以为事务添加堆复杂性,所以你必须权衡成本/效益。CMPXCHG的C++等式可能是::在C++中你可以做同样的事情。这是真的。我把一个简单的锁,解锁,除了计时循环之外没有其他功能,和ASM等价物进行比较。我只能推断.NETFramework或者Delphi(我同时使用这两个)都比简单的ASMCPMPXCHG功能做得多。所以我终于挖掘到了Delphi源程序。(奇怪的是,这是.Net上速度的一半)。这里有标志和API调用以及其他低效的开销。感谢您帮助我解决这个问题:)
#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;
};