我正在寻找一种方法来优化以下代码,为我开发的开源项目,或者通过将繁重的工作移动到另一个线程来提高性能。
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在包含文件夹-这可能是我的答案…?
好的,我将添加我自己的答案- 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
这里提到并非所有的容器操作在Windows上都是线程安全的。只有有限的几种方法。而且我不相信c++标准会提到线程安全容器。我可能错了,但是检查了标准没有问题
是否可以将客户端的通信卸载到单独的线程中?然后检查点可以使用线程本地存储来记录它们的命中,并且只需要与本地线程通信以在满时传递引用。然后,通信线程可以花时间将数据传递给实际的收集器,因为它不再位于热路径上。
您可以使用无锁队列。这里有一些文章