std::映射多线程中奇怪的资源争用
std::map strange resource contention in multithreading
我有一个std::map的奇怪行为(或者std::set,在这个场景中它们的行为似乎是一样的(。这可能是我对这应该如何工作有一个严重的误解我使用的是VS2010 SP1。
以这个函数为例:
extern time_t g_nElapsed;
UINT Thread(LPVOID _param)
{
UINT nRuns = (UINT)_param;
for(UINT i=0; i<nRuns; ++i)
{
time_t _1 = time(NULL);
std::set<UINT> cRandomSet;
cRandomSet.insert(1);
cRandomSet.insert(2);
cRandomSet.insert(3);
cRandomSet.insert(4);
g_nElapsed += (time(NULL) - _1);
}
return 0;
}
现在,如果我运行8个线程,每个线程有100000次迭代,g_nElpsed大约需要40秒。如果我用800000次迭代运行1个线程,g_nElpsed大约是5秒。我的印象是,对于任何合理数量的线程,g_nElpsed都应该大致相同。可以这么说。。。即使工作保持不变,处理器的使用量也会随着线程数量的增加而增加。然而,似乎与集合的某种资源争用会导致运行时增加。但为什么呢?这是线程本地。。。
我确信这是一个简单的误解和简单的解决方案,但我不太确定这里的问题是什么
以下代码没有表现出这种行为:
extern time_t g_nElapsed;
UINT Thread(LPVOID _param)
{
UINT nRuns = (UINT)_param;
for(UINT i=0; i<nRuns; ++i)
{
time_t _1 = time(NULL);
UINT n[4];
n[0] = 1;
n[1] = 1;
n[2] = 1;
n[3] = 1;
g_nElapsed += (time(NULL) - _1);
}
return 0;
}
您正在创建和销毁许多容器,每个容器都使用operator new
来分配内存。在许多系统上,这需要同步来管理像您这样典型的小分配中分配的可用内存。因此,您可能会在那里引发相当多的线程间争用。
您可以尝试不同的分配器,例如tcmalloc(http://goog-perftools.sourceforge.net/doc/tcmalloc.html)。它是专门为处理这个问题而设计的。
另一种方法是使用对象池或其他分配策略来避免完全使用标准分配机制。这将需要一些代码更改,而使用tcmalloc则不需要。
相关文章:
- 如何在没有死锁和/或争用的情况下正确使用 std::mutex C++?
- 并行块(线程清理器)之外的 OpenMP 中的争用条件;误报?
- 如何在C++中创建争用条件
- C++上的手动重置事件(来自 C#)实现:如何避免争用条件
- 作为随机数生成器的争用条件
- 设计低线程争用的多线程聊天服务器
- 智能指针析构函数争用条件
- 尽管互斥锁,线程中的争用条件
- ThreadSanitizer 报告的数据争用
- 在C++中递增和递减全局变量时的争用条件
- 线程清理器检测到数据争用,问题出在哪里?
- 为什么此代码不创建争用条件?
- 防止派生析构函数中的 vtable 数据争用
- __has_include() 和后续 #include 之间是否存在争用条件
- 一次加载整个缓存行以避免争用其中的多个元素
- 什么保证两个不相关的线程中的不同不相关对象没有(不可避免的)争用条件?
- 此工厂方法是否会导致争用条件?
- 争用条件 2 个线程交替
- 为什么此示例中没有使用 if 语句的数据争用?
- std::映射多线程中奇怪的资源争用