Выбор ответа Middle Производительность и кеш обновлено
False sharing
Вопрос
Четыре потока увеличивают каждый свой элемент массива std::atomic<long> counters[4]. Почему это медленнее, чем ожидалось?
Попробуйте сами
Выберите вариант, и откроется разбор.
Показать ответ и разбор
Коротко
Правильный ответ: Все счётчики в одной кеш-линии, ядра отбирают её друг у друга. Счётчики по 8 байт лежат в одной 64-байтной линии.
Варианты ответа
- Атомики всегда выполняются последовательно, даже на разных адресах
- Потоки не могут параллельно писать в один массив, ядра его блокируют
- Компилятор вставляет скрытый мьютекс в каждый
std::atomic<long> - Все счётчики в одной кеш-линии, ядра отбирают её друг у другаправильный ответ
Разбор
Счётчики по 8 байт лежат в одной 64-байтной линии. Каждая запись требует эксклюзивного владения линией, и протокол когерентности гоняет её между ядрами, хотя данные логически не общие. Лечится alignas(64) для каждого счётчика (или std::hardware_destructive_interference_size) либо локальными счётчиками с одной записью в конце.
- Атомики разных переменных выполняются параллельно, мешает именно общая линия.
- Работать параллельно с массивом можно.
std::atomic<long>на x86-64 lock-free, мьютекса нет.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.