Ну, последний вектор, скопированный в нить 0, равен objs[0].c
.Первый вектор, скопированный в потоке 1: objs[1].a[0].a
.Таким образом, если их два блока распределенных данных занимают одну и ту же строку кэша (64 байта или что-то еще для этого ЦП), у вас будет ложное совместное использование.
И, конечно, то же самое верноиз любых двух задействованных векторов, но ради конкретного примера я сделал вид, что поток 0 запускается первым и выполняет свое распределение до того, как поток 1 начинает выделять, и что распределитель имеет тенденцию делать последовательные выделения смежными.
reserve()
может помешать частям этого блока, на котором вы на самом деле воздействуете, занимать одну и ту же строку кэша.Другим вариантом может быть выделение памяти для каждого потока - если блоки этих векторов выделяются из разных пулов, они не могут занимать одну и ту же строку, если не занимают пулы.
Если у вас нетв распределителях потоков проблема может быть в распределении памяти, если DoWork
много перераспределяет векторы.Или это может быть конфликт на любом другом общем ресурсе, используемом DoWork
.По сути, представьте, что каждый поток тратит 1 / K своего времени на выполнение чего-то, что требует глобального монопольного доступа.Тогда может показаться, что он достаточно хорошо распараллеливается до определенного числа J <= K, и в этот момент получение эксклюзивного доступа значительно сказывается на ускорении, поскольку ядра тратят значительную часть времени простоя.За исключением K ядер, с дополнительными ядрами улучшения почти не происходит, потому что общий ресурс не может работать быстрее. </p>
В конце этого, представьте себе какую-то работу, которая тратит 1 / K своего времени, удерживая глобальную блокировку.и (K-1) / K своего времени ожидания на I / O.Тогда проблема кажется смущающей параллелью почти до K потоков (независимо от количества ядер), после чего она останавливается.
Так что, не сосредотачивайтесь на ложном совместном использовании, пока не исключите true Поделиться; -)