Редактировать: Было внесено существенное изменение после некоторого дальнейшего сужения того, что действительно меня сбивало с толку. Я попытался сохранить общее представление о вопросе, чтобы сохранить актуальность полученных замечательных ответов.
@Kay, приведенный вами пример не имеет ничего общего с «выборкой устаревшей строки кеша», он сохраняет согласованность кеша и соответствует модели упорядочения памяти TSO (которая действительно слабее, чем последовательная согласованность, но далеко не «слабая»).
@ PaulA.Clayton Я думаю, что запутал ситуацию, связав пример, что делает имеет отношение к согласованности. Извини за это.
@Leeor Я думаю, что запутал ситуацию, связав пример, что делает имеет отношение к согласованности. Извини за это.
Ваш вопрос все еще не ясен после редактирования. Вы должны расширить второй и третий пункты вопроса.
Кеши в основных процессорах Intel находятся полностью согласованы (для обычных типов памяти и обычных операций чтения и записи), поэтому основание для вашего вопроса (а это не так), вероятно, неверно. Да, сама память модели x86 допускает некоторое ограниченное переупорядочение (нагрузки, проходящие через более ранние хранилища), но это в основном результат переупорядочения в ядре из-за буфера хранилища и других эффектов нарушения порядка, а не из-за некогерентных кешей . Не существует «возможной согласованности» того типа, который вы описываете. Если ядро не отвечает «немедленно» на отслеживание, оно должно просто ждать.





Re: ваше редактирование, которое кажется новым вопросом: верно, переадресация магазина "нарушает" согласованность. Ядро может видеть свои собственные хранилища раньше, чем любое другое ядро может их видеть. Буфер хранилища не согласован.
Правила упорядочивания памяти x86 требуют, чтобы загрузки становились глобально видимыми в программном порядке, но позволяют ядру загружать данные из своих собственных хранилищ, прежде чем они станут глобально видимыми. Не обязательно притвориться, что он ждал, и проверить, нет ли неправильных предположений о порядке памяти, как это происходит в других случаях выполнения загрузки раньше, чем того требует модель памяти.
Также связанные; Может ли x86 переупорядочить узкое хранилище с более широкой загрузкой, которая полностью его содержит? - это конкретный пример буфера хранилища + пересылка хранилища, нарушающего обычные правила упорядочивания памяти. См. эта коллекция сообщений списка рассылки Линуса Торвальдса, в котором объясняется влияние переадресации магазина на упорядочение памяти (и как это означает, что предложенная схема блокировки не работает).
Без согласованности вообще, как бы вы атомарно увеличили общий счетчик или реализовали другие атомарные операции чтения-изменения-записи, которые необходимы для реализации блокировок или для использования непосредственно в коде без блокировки. (См. Может ли num ++ быть атомарным для int num?).
lock add [shared_counter], 1 в нескольких потоках одновременно никогда не теряет счет на фактическом x86, потому что префикс lock заставляет ядро сохранять исключительное владение строкой кеша от загрузки до тех пор, пока хранилище не зафиксируется на L1d (и, таким образом, станет глобально видимым).
Система без согласованных кешей позволила бы каждому потоку увеличивать свою собственную копию общего счетчика,, а затем последнее значение в памяти будет происходить от того, какой поток последним сбрасывал эту строку.
Разрешение различным кешам хранить конфликтующие данные для одной и той же строки в течение длительного времени, даже когда происходят другие загрузки / сохранения, и через барьеры памяти, допустит всевозможные странности.
Это также нарушило бы предположение о том, что чистый магазин сразу становится видимым для других ядер. Если бы у вас вообще не было согласованности, то ядра могли бы продолжать использовать свою кэшированную копию общей переменной. Итак, если вы хотите, чтобы читатели заметили обновления, вам придется clflush перед каждым чтением общей переменной, что делает общий случай дорогостоящим (когда никто не изменял данные с момента последней проверки).
MESI похож на систему push-уведомлений, вместо того, чтобы заставлять каждого читателя повторно проверять свой кеш при каждом чтении.
MESI (или когерентность в целом) позволяет таким вещам, как RCU (чтение-копирование-обновление) иметь нулевые накладные расходы для читателей (по сравнению с однопоточным) в случае, когда общая структура данных не была изменена.. См. https://lwn.net/Articles/262464/ и https://en.wikipedia.org/wiki/Read-copy-update. Основная идея состоит в том, что вместо блокировки структуры данных писатель копирует все, изменяет копию, а затем обновляет общий указатель, чтобы указать на новую версию. Так что читатели всегда не ждут; они просто разыменовывают (атомарный) указатель, и данные остаются в их кэше L1d.
Аппаратная поддержка когерентности чрезвычайно важна, и почти каждая архитектура SMP с общей памятью использует ее. Даже ISA с гораздо более слабыми правилами упорядочивания памяти, чем x86, например PowerPC, используют MESI.
Многоядерные процессоры и GPGPU - это архитектуры с общей памятью, которые обычно не реализуют согласованность кеша или предлагают ограниченную форму согласованности.
@HadiBrais: поэтому для увеличения общего атома в GPGPU потребуется дорогостоящий явный барьер для обеспечения согласованности, как предполагает ответ @Bee? Я упустил эту возможность, когда писал это. (И когда вы говорите manycore, вы исключаете Xeon Phi, верно? Я думаю, что он реализует модель разделяемой памяти x86.)
Процессор Xeon Phi согласован внутри себя и с другими процессорами. Сопроцессор Xeon Phi согласован только внутри себя, а не с другими процессорами или сопроцессорами. В этом отличие от многоядерных процессоров с несколькими сокетами.
GPGPU имеют когерентный L2, но не L1.
Intel SCC вообще не является аппаратно-согласованным.
@PeterCordes - эти несогласованные архитектуры обычно имеют явные инструкции связи, которые можно использовать для синхронизации определенных областей памяти, поэтому что-то гораздо более богатое, чем барьеры памяти. Конечно, вы обычно не ориентируетесь на них с помощью стандартной атомики C++, поэтому «проблемы» с реализацией C++ или подобных процессору атомарных операций и ограждений на самом деле не возникает.
@BeeOnRope: Хорошо, в этом есть смысл. И да, отсутствие обычного мелкозернистого многопоточного кода с общей памятью позволяет этим архитектурам использовать другую модель согласованности, которая не подходит для обычного x86 или PowerPC, на которых выполняются подобные рабочие нагрузки.
Эти комментарии немного выше моей головы: P. Однако рад видеть такие глубокие знания. Надеюсь, не преуменьшить великий ответ, который дал Питер, но я реструктурировал вопрос, чтобы выявить область моего замешательства; а именно «согласованность» «представления памяти» каждого ядра, когда задействованы буферы хранения.
Так, например, учитывая ваш первоначальный ответ, я бы также спросил, с буферами хранилища, как атомики будут работать? Они должны сначала очистить буфер хранилища, а затем заблокировать строку (строки) кеша?
@Kay: Если вы надеетесь, что @ BeeOnRope увидит ваши комментарии, вам нужно использовать @, чтобы уведомить его. (Но вы можете уведомить только одного пользователя за комментарий. Этот комментарий будет пинговать вас, а не Пчелу.)
@Kay: Вы имеете в виду атомику чтения-изменения-записи? Нравится xchg или lock add? На x86 атомарные операции в любом случае являются полными барьерами памяти, поэтому да, они истощают буфер хранилища, а также удерживают заблокированную строку кеша. На слабо упорядоченном ISA (как и на большинстве RISC) в этом не было бы необходимости; LL / SC может завершиться успешно, пока в буфере хранилища еще есть невыполненные хранилища промахов кэша. Но да, модель памяти x86 этого не допускала.
@PeterCordes Re: Ваше изменение: «ядру явно разрешено видеть свои собственные хранилища, прежде чем они станут глобально видимыми». Я считать так; см. Intel SDM Vol3: 8.2.3.5. «Модель упорядочивания памяти позволяет двум процессорам одновременно видеть одновременное хранение данных двумя процессорами в разном порядке; в частности, каждый процессор может воспринимать свое собственное хранилище раньше другого».
@PeterCordes Я предполагаю, что это из-за того, что вы заявили, как намекнули Intel: «На практике переупорядочение в этом примере может возникнуть в результате пересылки буфера хранилища. В то время как хранилище временно хранится в буфере хранилища процессора. , он может удовлетворять собственные нагрузки процессора, но не виден (и не может удовлетворять) нагрузкам других процессоров ".
@Kay: Ага, спасибо за проверку. Это то, о чем я думал.
@Kay: Я вспомнил предыдущий вопрос SO, который имеет отношение к делу; добавил ссылку на свой ответ.
@PeterCordes Привет, Питер. Спасибо за отличный вопрос и комментарии. Вынужденный принять только один ответ не оправдывает ваших усилий.
@ PaulA.Clayton. Верно, и я это понимаю; но как это ответить на вопрос? Я не упомянул согласованность - просто согласованность: получение устаревшей строки кеша.