代码之家  ›  专栏  ›  技术社区  ›  namezero

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

  •  0
  • namezero  · 技术社区  · 11 年前

    我对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;
    }
    
    1 回复  |  直到 11 年前
        1
  •  3
  •   John Zwinck    11 年前

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

    您可以尝试不同的分配器,例如tcmalloc( http://goog-perftools.sourceforge.net/doc/tcmalloc.html ). 它是专门为处理这个问题而设计的。

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