Ответ на этот вопрос сильно зависит от архитектуры и уровня кэша, а также от того, где на самом деле работают потоки.
Например, недавние многоядерные процессоры Intel имеют кэш-память L1 для каждого ядра.и кэш L2, который совместно используется ядрами в одном и том же пакете ЦП;однако разные пакеты ЦП будут иметь свои собственные кэши L2.
Даже в том случае, если ваши потоки работают на двух ядрах в одном пакете, даже если оба потока обращаются к данным в пределах одной и той же кеш-линии, у вас будет эта подпрыгиваниемежду двумя кешами L1. очень неэффективно, и вы должны разработать свой алгоритм, чтобы избежать этой ситуации.
В нескольких комментариях спрашивалось, как избежать этой проблемы.
В сущности, это на самом деле не особенно сложно - вы просто хотите избежать одновременной попытки доступа двух потоков к данным, расположенным в одной строке кэша, где по крайней мере один поток записывает данные.(Поскольку все потоки только читают данные, проблем нет - на большинстве архитектур данные только для чтения могут присутствовать в нескольких кэшах).
Для этого вам нужнонеобходимо знать размер строки кэша - это зависит от архитектуры, но в настоящее время большинство чипов семейства x86 и x86-64 используют 64-байтовую строку кэша (обратитесь к руководству по архитектуре для других архитектур).Вам также необходимо знать размер ваших структур данных.
Если вы попросите свой компилятор выровнять интересующую общую структуру данных по границе в 64 байта (например, ваш массив output
), то выЗнайте, что он начнется в начале строки кэша, и вы также можете вычислить, где находятся границы последующих строк кэша.Если ваш int
равен 4 байта, то каждая строка кэша будет содержать ровно 8 int
значений.До тех пор, пока массив начинается на границе линии кеша, с output[0]
по output[7]
будет на одной строке кеша, а с output[8]
до output[15]
на следующей.В этом случае вы должны разработать свой алгоритм так, чтобы каждый поток работал с блоком смежных int
значений, кратных 8.
Если вы храните сложные struct
типы, а не простые int
, утилита pahole
будет полезна.Он проанализирует типы struct
в вашем скомпилированном двоичном файле и покажет вам макет (включая отступы) и общий размер.Затем вы можете настроить struct
s, используя этот вывод - например, вы можете вручную добавить некоторые отступы, чтобы ваш struct
был кратным размеру строки кэша.
В системах POSIXФункция posix_memalign()
полезна для выделения блока памяти с указанным выравниванием.