std :: map多线程中的奇怪资源争用

时间:2013-02-26 12:39:33

标签: c++ multithreading map resources contention

我对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个线程,每个线程有100,000次迭代,g_nElapsed将大约为40秒。 如果我运行1个线程并进行800,000次迭代,则g_nElapsed将大约为5秒。 我的印象是,对于任何合理数量的线程,g_nElapsed应该大致相同。 可以这么说......即使工作保持不变,处理器的使用也会随着线程的数量而增加。 但是,似乎与该集的某种资源争用会导致运行时增加。 但为什么?这是本地线程......

我确信这是一个简单的误解和一个简单的修复,但我不太确定这里的问题是什么。

以下代码不会出现此行为:

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;
}

1 个答案:

答案 0 :(得分:3)

您正在创建和销毁许多容器,每个容器都使用operator new来分配内存。在许多系统上,这需要同步来管理在像您这样的典型小分配上分配的空闲内存。所以你可能会在那里招致相当多的跨线程争用。

您可以尝试使用其他分配器,例如tcmalloc(http://goog-perftools.sourceforge.net/doc/tcmalloc.html)。它专门用于解决这个问题。

另一种方法是使用对象池或其他分配策略来避免完全使用标准分配机制。这将需要一些代码更改,而使用tcmalloc则不需要。