GitHub 2.2k ЗвездаПуть к тому, чтобы стать Java-инженером, почему бы тебе не прийти и не узнать?
GitHub 2.2k ЗвездаПуть к тому, чтобы стать Java-инженером, ты правда не хочешь узнать?
GitHub 2.2k ЗвездаПуть к тому, чтобы стать Java-инженером, ты действительно уверен, что не хочешь узнать?
существуетЕсли кто-то спросит вас, что такое модель памяти Java, отправьте ему эту статью.В этой статье мы рассмотрели все тонкости модели памяти Java.
Мы упоминали в статье, что есть разница в скорости обработки ЦП и основной памяти, чтобы соответствовать этому разрыву, улучшить возможности компьютера, люди увеличили многоуровневый кэш между ЦП и основной памятью. Каждый ЦП будет иметь кэш-память L1, L2 или даже L3, в многоядерном компьютере будет несколько ЦП, затем будет многоуровневый кеш, тогда данные между многоуровневым кешем могут иметь противоречивые явления. Для решения этой проблемы существует модель памяти. Модель памяти определяет спецификацию поведения операций чтения-записи многопоточных программ в системах с общей памятью. Эти правила используются для регулирования операций чтения и записи в память, чтобы обеспечить правильность выполнения инструкций.
Я не знаю, ребята, думали ли вы над этим вопросом:Как модель памяти гарантирует когерентность кэша?
Далее мы попытаемся ответить на этот вопрос. Во-первых, когерентность кеша — это проблема, вызванная введением кеша, так что это проблема, которую должны решить многие производители процессоров. Чтобы решить проблему несоответствия кэшированных данных, упомянутую выше, люди предложили множество решений, обычно это следующие два решения:
1. Добавляя в шину
LOCK#
способ блокировки.2, через протокол когерентности кэша.
В ранних процессорах это делалось путем добавленияLOCK#
Форма блокировки для решения проблемы несогласованности кеша. Поскольку связь между ЦП и другими компонентами осуществляется через шину, если шина добавленаLOCK#
Блокировка, то есть блокирование доступа других ЦП к другим компонентам (таким как память), так что только один ЦП может использовать память этой переменной. выдается на автобусLCOK#
Сигнал блокировки, затем, только дождавшись завершения выполнения этого кода, другие ЦП могут считывать переменные из своей памяти, а затем выполнять соответствующие операции. Это решает проблему несогласованности кэша.
Но поскольку другие процессоры не могут получить доступ к памяти, пока шина заблокирована, это приведет к неэффективности. Поэтому появилось второе решение, которое решает проблему когерентности кеша с помощью протокола когерентности кеша.
Протокол когерентности кэша
Протокол Cache Coherence Protocol, наиболее известный из которых — протокол Intel MESI, гарантирует согласованность копий общих переменных, используемых в каждом кэше.
Основная идея Mesi: когда CPU записывает данные, если он находит, что управляемая переменная - это общая переменная, то есть копия переменной существует в других процессорах, она отправит сигнал для уведомления других процессоров Чтобы установить линию кэша переменной переменной в неверное состояние, поэтому, когда другие процессоры должны прочитать эту переменную и найти, что строка кэша, которая кэширует переменную в собственном кэш-памяти, она недействительна, она перечитает его из памяти.
В протоколе MESI каждый кэш может иметь 4 состояния:
M(Modified): Эта строка данных действительна, данные были изменены, и они несовместимы с данными в памяти, и данные существуют только в этом кэше.
E(Exclusive): Эта строка данных действительна, данные согласуются с данными в памяти, и данные существуют только в этом кэше.
S(Shared): Эта строка данных действительна, данные согласуются с данными в памяти, и данные существуют во многих кэшах.
I(Invalid): Эта строка данных недействительна.
Подробнее о Mesi не будет введен здесь.
Однако стоит отметить, что в традиционном протоколе MESI есть два варианта поведения, которые требуют относительно больших затрат на выполнение.
Один из них — пометить строку кэша как недействительную, а другой — записать новые данные, когда текущее состояние строки кэша — недопустимое. Таким образом, ЦП уменьшает задержку таких операций с помощью компонентов Store Buffer и Invalidate Queue.
Как показано на рисунке:
Когда ЦП записывает, он сначала отправляет сообщение Invalid другим ЦП, а затем записывает текущие записанные данные в буфер хранения. затем асинхронно вкогда-тоНастоящая запись в кэш.
Если текущее ядро ЦП хочет прочитать данные из кэша, ему необходимо просканировать буфер хранилища перед чтением кэша.
Однако в это время другое ядро ЦП не видит данные в буфере хранения текущего ядра, а данные для ожидания до тех пор, пока данные в буфере хранения не будут перенесены в кэш, вызовут только аварийное переключение.
Когда ядро ЦП получает сообщение Invalidate, оно записывает это сообщение в свою очередь Invalidate Queue, а затемасинхронныйУстановите его в недопустимое состояние.
В отличие от Store Buffer, текущее ядро ЦП не сканирует часть Invalidate Queue при использовании Cache, поэтому можетГрязные чтения в течение очень короткого периода времени.
Поэтому для решения проблемы когерентности кэша типичным решением является протокол когерентности кэша MESI.
Протокол MESI может гарантировать согласованность кэша, но не может гарантировать производительность в реальном времени.
модель памяти
Модель когерентности кэша была представлена ранее, а затем давайте рассмотрим модель памяти. Мы сказали, что модель памяти определяет набор спецификаций, обеспечивающих видимость, упорядоченность и атомарность при доступе к общим переменным несколькими потоками. (Для получения дополнительной информации см.Если кто-то спросит вас, что такое модель памяти Java, отправьте ему эту статью.)
Если модель памяти расширена, она обычно относится к модели согласованности памяти (Memory Sequential Consistency Model).
Как упоминалось ранее, когерентность кеша, согласованность памяти, здесь нужно сказать, не означает, что читатель должен заниматься Монголией, но дает читателям более четкое сравнение.
Cache Coherence, решайте проблему согласованности данных между несколькими копиями кеша.
Согласованность памяти гарантирует, какое значение может прочитать многопоточная программа при доступе к памяти.
Сначала рассмотрим следующую программу:
初始:x=0 y=0
Thread1:
S1:x=1
L1:r1=y
Thread2:
S2:y=2
L2:r2=x
Среди них S1, S2, L1, L2 — коды операторов (S — Store, L — Load), r1 и r2 — два регистра. x и y - две разные переменные памяти. Какими могут быть значения r1 и r2 после завершения выполнения двух потоков?
Отметив, что потоки выполняются одновременно и попеременно, ниже приведены возможные последовательности выполнения и соответствующие результаты:
S1 L1 S2 L2 那么r1=0 r2=2
S1 S2 L1 L2 那么r1=2 r2=1
S2 L2 S1 L1 那么r1=2 r2=0
Все это ожидаемо и разумно. Но в архитектуре x86 очень вероятно получить результаты типа r1=0 r2=0.
если нетMemory Consistency
, вывод программного кода, написанного программистом, неопределен.
следовательно,Memory Consistency
Это протокол между программистами (языками программирования), компиляторами и процессорами. Этот протокол гарантирует, какое значение программа получит при доступе к памяти.
Проще говоря, непротиворечивость памяти заключается в том, чтобы гарантировать, что результаты работы программы в параллельных сценариях будут такими же, как ожидали программисты (конечно, посредством блокировки и т. д.), включая атомарность, упорядоченность и видимость в параллельном программировании. Когерентность кэша — это видимость в параллельном программировании.
При реализации многих моделей памяти гарантия когерентности кеша гарантируется аппаратным протоколом когерентности кеша.Следует отметить, что упомянутая здесь модель памяти является моделью памяти компьютера, а не моделью памяти Java.
Суммировать
проблемы с когерентностью кэша. Проблема на аппаратном уровне относится к проблеме несогласованности данных между кэшами из-за нескольких наборов кэшей в многоядерном компьютере.
PS: Здесь нужно повторить: в многопоточности Java каждый поток имеет свою рабочую память и должен взаимодействовать с основной памятью. Оперативная память здесь и кэш компьютерного железа не одно и то же, но их можно сравнивать друг с другом. Следовательно, проблема видимости параллельного программирования вызвана несогласованностью данных локальной памяти между потоками и не имеет ничего общего с кешем компьютера.
Протокол когерентности кэша. Протокол MESI обычно используется для решения проблемы когерентности кэша.
Модель согласованности памяти. Защищайте проблемы с аппаратным обеспечением компьютера, в основном для решения проблем атомарности, упорядочения и согласованности в параллельном программировании.
Время для достижения модели согласованности может использоваться в модели Cache Coherency.
считать
Наконец, позвольте мне оставить вас с вопросом для размышления:
Поскольку на аппаратном уровне уже существует протокол когерентности кеша, который может обеспечить когерентность кеша, то есть видимость в параллельном программировании, зачем программистам использовать такие ключевые слова, как volatile и synchronized, при написании многопоточного кода?Гарантированная видимость?
Что касается ответа на этот вопрос, я отвечу на него в следующем подробном введении в volatile. Добро пожаловать на мой блог (www.hollischuang.com) и публичный аккаунт (Холлис) узнать впервые.
использованная литература
Расскажите об атомарных переменных, блокировках и барьерах памяти.
Непротиворечивость памяти и когерентность кэша
Если есть способ, но нет искусства, искусство может быть достигнуто; если есть искусство, но нет пути, оно заканчивается на пути; добро пожаловать, чтобы обратить внимание на публичный аккаунт [Java Way], давайте воспользуемся способом, чтобы овладеть искусством и знать путь с искусством;