Безопасно ли это делать?
При условии, что ваша модификация данных представляется безопасной и защищенной критическими секциями, блокировками или чем-то еще, этот вид доступа совершенно безопасен для доступа к оборудованию.
Поток А действительно обновляет массив или просто копию в кеше?
Просто копия в кеше.Большинство кешей в настоящее время с обратной записью и просто записывают данные обратно в память, когда строка извлекается из кеша, если она была изменена.Это в значительной степени улучшает пропускную способность памяти, особенно в многоядерном контексте.
НО все происходит , как если бы память была обновлена.
Для процессоров с общей памятью, как правило, существуют протоколы когерентности кэша (за исключением некоторых процессоров для приложений реального времени),Основная идея этих протоколов заключается в том, что состояние связано с каждой строкой кэша.
Состояние описывает информацию, касающуюся строки в кэше различных процессоров.
Эти состояния указывают, например,если строка присутствует только в текущем кэше или совместно используется несколькими кэшами, синхронно с памятью, недействительна ... См., например, это описание популярного протокола когерентности кэша MESI.
Так что же происходит, когда строка кэша записана и также присутствует в другом процессоре?
Благодаря состоянию кэш знает, что один или несколько других процессоров также имеют копию строки, и он отправит недействительный кодсигнал.Строка будет признана недействительной в других кэшах, и когда они захотят прочитать или записать ее, им придется перезагрузить ее содержимое.На самом деле, эта перезагрузка будет обслуживаться кешем, имеющим действительную копию для ограничения доступа к памяти.
Таким образом, хотя данные записываются только в кеш, поведение аналогично ситуации, в которой данные были бы записаны в память.
НО, несмотря на то, что функционально аппаратное обеспечение будетДля обеспечения правильности передачи необходимо учитывать существование кэша, чтобы избежать снижения производительности.
Предположим, что кэш A обновляет строку, а кэш B читает ее.Всякий раз, когда кэш A записывает, строка в кеше B становится недействительной.И всякий раз, когда кэш B хочет прочитать его, если строка была признана недействительной, он должен извлечь ее из кеша A. Это может привести ко многим переносам строки между кешами и сделать неэффективной систему памяти.
ИтакЧто касается вашего примера, вероятно, 10 не очень хорошая идея, и вам следует использовать информацию о кешах для улучшения обмена между отправителем и получателем.
Например, если вы используете Pentium с 64-байтовыми строками кэша,Вы должны объявить X как
_Alignas(64) float X[100];
Таким образом, начальный адрес X
будет кратен 64 и соответствует границам строк кэша.Определитель _Alignas
существует с C17, и, включив stdalign.h, вы также можете использовать аналогично alignas(64)
.До C17 в большинстве компиляторов было несколько расширений для выравнивания размещения.
И, конечно, вы должны указать процессу B для чтения данных только тогда, когда записана полная строка в 64 байта (16 значений с плавающей запятой).
Таким образом, когда поток B получает доступ к данным, строка кэша больше не будет изменяться потоком A, и будет иметь место только одна первоначальная передача между кэшами A и B.Это уменьшение количества передач между кешами может существенно повлиять на производительность в зависимости от вашей программы.