std :: map странный конфликт ресурсов в многопоточности

У меня странное поведение с 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;
}

0

Решение

Вы создаете и уничтожаете много контейнеров, и каждый использует operator new выделить память. Во многих системах это требует синхронизации для управления свободной памятью, которая выделяется при типичных небольших распределениях, таких как у вас. Таким образом, вы, вероятно, подвергаетесь довольно большим конфликтам между потоками.

Вы можете попробовать другой распределитель, такой как tcmalloc (http://goog-perftools.sourceforge.net/doc/tcmalloc.html). Он специально разработан, чтобы справиться с этим.

Другой подход заключается в использовании пула объектов или другой стратегии распределения, чтобы полностью не использовать стандартный механизм распределения. Это потребовало бы некоторых изменений кода, тогда как использование tcmalloc — нет.

3

Другие решения

Других решений пока нет …