4

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

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 块),当它向主机进程发出信号时,它会发出信号。显然,这对于每个仪表点来说都非常重,我想让影响更轻。

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

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


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

4

4 回答 4

1

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

使用这篇MSDN 文章中描述的详细信息,我实现了并发队列(和任务以及我的第一个 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
于 2011-08-30T13:46:12.987 回答
0

这里提到并非所有容器操作在 Windows 上都是线程安全的。只有有限的几种方法。而且我不相信 C++ 标准提到了线程安全容器。我可能错了,但检查了标准没有出现

于 2011-08-30T12:23:35.633 回答
0

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

于 2011-08-30T12:27:07.070 回答
0

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

于 2011-08-30T12:40:53.670 回答