线程安全队列是一个好方法吗?

时间:2011-08-30 12:10:46

标签: c++ performance boost c++11 opencover

我正在寻找一种优化以下代码的方法,对于我开发的开源项目,或者通过将繁重的工作转移到另一个线程来使其更高效。

void ProfilerCommunication::AddVisitPoint(ULONG uniqueId)
{
    CScopedLock<CMutex> lock(m_mutexResults);
    m_pVisitPoints->points[m_pVisitPoints->count].UniqueId = uniqueId;
    if (++m_pVisitPoints->count == VP_BUFFER_SIZE)
    {
        SendVisitPoints();
        m_pVisitPoints->count=0;
    } 
}

当调用每个访问点时,上面的代码由OpenCover探查器(用C ++编写的.NET的开源代码覆盖工具)使用。互斥锁用于保护某些共享内存(在多个进程32/64位和C ++ / C#之间共享的64K块),当它充满时它会向主机进程发出信号。显然,对于每个仪表点而言,这都非常重,我想让影响更轻。

我正在考虑使用由上述方法推送的队列和一个线程来弹出数据并填充共享内存。

Q值。我可以使用C ++(Windows STL)中的线程安全队列 - 还是无锁队列,因为我不想用另一个问题替换一个问题?人们认为我的方法合理吗?


编辑1:我刚刚在include文件夹中找到concurrent_queue.h - 这可能是我的回答......?

4 个答案:

答案 0 :(得分:1)

好的,我会添加自己的答案 - concurrent_queue效果非常好

使用此MSDN article中描述的详细信息我实现了并发队列(以及任务和我的第一个C ++ lambda表达式:))我没有花太多时间思考,因为它是一个尖峰。

inline void AddVisitPoint(ULONG uniqueId) { m_queue.push(uniqueId); }

...
// somewhere else in code

m_tasks.run([this]
{
    ULONG id;
    while(true)
    {
         while (!m_queue.try_pop(id)) 
            Concurrency::Context::Yield();

        if (id==0) break; // 0 is an unused number so is used to close the thread/task
        CScopedLock<CMutex> lock(m_mutexResults);
        m_pVisitPoints->points[m_pVisitPoints->count].UniqueId = id;
        if (++m_pVisitPoints->count == VP_BUFFER_SIZE)
        {
            SendVisitPoints();
            m_pVisitPoints->count=0;
        }
    }
});

结果:

  • 无仪器应用= 9.3
  • 旧仪器处理程序的应用程序= 38.6
  • 使用新仪器处理程序的应用程序= 16.2

答案 1 :(得分:0)

Here it mentions not all container operations are thread safe on Windows. Only a limited number of methods。我不相信C ++标准提到线程安全容器。我可能错了,但检查标准没有出现

答案 2 :(得分:0)

是否可以将客户端的通信卸载到单独的线程中?然后检查点可以使用线程本地存储来记录它们的命中,并且只需要与本地线程通信以在满时传递引用。然后,通信线程可以花时间将数据传递给实际的收集器,因为它不再位于热路径上。

答案 3 :(得分:0)

您可以使用无锁队列。 Herb Sutter有一些文章here