#опытным
В прошлом посте упомянул false sharing - ситуации в многопоточном программировани, когда данные не связаны и независимы, а на самом деле операции над одними данными влияют на другие за счет того, что они лежат в одной кэш линии.
Там я использовал выравнивание по границе 64 байта - это типичный размер кэш-линии на современных процессорах.
Но на эту чиселку нельзя надеяться как на первоисточник. Железо бывает разное и надо уметь узнавать размер кэш-линии для конкретного процессора.
Для этого начиная с С++17 в стандарте появились константы std::hardware_destructive_interference_size и std::hardware_constructive_interference_size.
На практике они почти всегда равны размеру кэш линии, но смысл у них немного разный.
std::hardware_destructive_interference_size - Минимальное смещение, которое гарантирует отсутствие false sharing.
std::hardware_constructive_interference_size - Максимальный размер участка памяти, внутри которого гарантируется true sharing.
С false sharing мы разобрались:
struct GuaranteeFalseSharingAbsence
{
alignas(std::hardware_destructive_interference_size ) std::atomic<uint64_t> counter1;
alignas(std::hardware_destructive_interference_size ) std::atomic<uint64_t> counter2;
};
Помещаем два атомарных счетчика в разные кэш-линии и их изменения никак не влияют друг на друга.
А что такое true sharing?
Это ситуация, когда данные попадают в одну кэш линию.
Иногда мы хотим убедиться, чтобы данные обязательно попадали всегда именно в одну кэш линию. Для этого вся структура выравнивается по границе hardware_constructive_interference_size и все, что лежит в структуре, попадет внутрь одной линии.
struct alignas(std::hardware_constructive_interference_size) A {
std::uint32_t one;
std::uint32_t two;
};Конкретных кейсов не могу привести, если у кого есть опыт работы с hardware_constructive_interference_size, то отпишитесь, будет интересно почитать.
Спасибо, @topin89, за идею для поста)
Share with others. Stay cool.
#cpp17