Подтвердить что ты не робот

Является ли модель памяти Java (JSR-133), что вход в монитор очищает кеш-память процессора?

Есть что-то, что меня пугает с моделью памяти Java (если я все правильно понимаю). Если есть два потока A и B, нет никаких гарантий того, что B когда-либо увидит значение, написанное A, если оба A и B не синхронизируются на одном мониторе.

Для любой системной архитектуры, которая гарантирует согласованность кеширования между потоками, нет проблем. Но если архитектура не поддерживает когерентность кэша в оборудовании, это по существу означает, что всякий раз, когда поток входит в монитор, все сделанные ранее изменения памяти должны быть записаны в основную память, а кеш должен быть недействительным. И это должен быть кеш данных whole, а не только несколько строк, так как у монитора нет информации о том, какие переменные в памяти он защищает. Но это, безусловно, повлияет на производительность любого приложения, которое необходимо часто синхронизировать (особенно такие, как очереди заданий с работами с короткими работами). Так может ли Java работать на архитектуре без аппаратной кеширования? Если нет, почему модель памяти не дает более надежных гарантий относительно видимости? Не было бы более эффективным, если бы язык требовал информации о том, что охраняется монитором?

Как я вижу, модель памяти дает нам худшее из обоих миров, абсолютная необходимость синхронизации, даже если когерентность кэша гарантирована в аппаратном обеспечении, а с другой - плохая производительность на некогерентных архитектурах (полная очистка кеша). Так что не должно быть более строгим (требуется информация, охраняемая монитором) или больше потерять и ограничить потенциальные платформы кеш-когерентными архитектурами?

Как и сейчас, это не имеет для меня слишком большого смысла. Может кто-нибудь выяснить, почему была выбрана эта конкретная модель памяти?


EDIT: Мое использование строгих и проигравших было неудачным выбором в ретроспективе. Я использовал "строгий" для случая, когда делаются меньше гарантий и "теряются" для противоположного. Чтобы избежать путаницы, вероятно, лучше говорить о более сильных или слабых гарантиях.

4b9b3361

Ответ 1

абсолютная необходимость синхронизации, даже если когерентность кэша гарантирована аппаратное обеспечение

Да, но тогда вам нужно только рассуждать о модели памяти Java, а не о конкретной аппаратной архитектуре, в которой ваша программа работает. Кроме того, это не только аппаратное обеспечение, то компилятор и JIT могут изменить порядок инструкций, вызывающих проблему видимости. Конструкции синхронизации в Java обеспечивают видимость и атомарность последовательно на всех возможных уровнях преобразования кода (например, компилятор /JIT/CPU/cache ).

а с другой - плохая производительность на некогерентных архитектурах (полный кеш-флеши)

Возможно, я неправильно понял s/t, но с некогерентной архитектурой вам все равно нужно синхронизировать критические разделы. В противном случае вы столкнетесь со всеми условиями гонки из-за переупорядочения. Я не понимаю, почему модель памяти Java делает это хуже.

не должен быть более строгим (требуется информацию, охраняемую монитор)

Я не думаю, что можно сказать, что процессор вообще скрывает какую-либо часть кэша. Лучшее, что может сделать компилятор, это испускать заграждения памяти и позволить ЦП решать, какие части кеша нужно смывать - он еще более грубый, чем тот, который вы ищете, я полагаю. Даже если возможно более мелкомасштабное управление, я думаю, что это затруднит параллельное программирование (это уже достаточно сложно).

AFAIK, Java 5 MM (как и .NET CLR MM) является более "строгим", чем модели памяти общих архитектур, таких как x86 и IA64. Поэтому он делает рассуждения об этом относительно проще. Тем не менее, очевидно, что он не должен предлагать s/t ближе к последовательной согласованности, поскольку это значительно ухудшит производительность, поскольку может быть применено меньшее количество оптимизаций компилятора/JIT/CPU/cache.

Ответ 2

Существующие архитектуры гарантируют согласованность кеша, но они не гарантируют последовательную согласованность - две вещи разные. Начиная с seq. согласованность не гарантируется, некоторые переупорядочивания разрешены аппаратным обеспечением, и вам нужны критические разделы для их ограничения. Критические разделы удостоверяются, что то, что один поток пишет, становится видимым для другого (т.е. Предотвращает расы данных), а также предотвращает классические условия гонки (если два потока увеличивают одну и ту же переменную, вам нужно, чтобы для каждого потока считалось текущее значение и запись нового значения неделимы).

Кроме того, модель исполнения не так дорого, как вы описали. В большинстве существующих архитектур, которые являются кеш-когерентными, но не последовательно последовательными, когда вы освобождаете блокировку, вы должны очищать ожидающие записи в памяти, а когда вы ее приобретаете, вам может понадобиться сделать что-то, чтобы будущие чтения не читали устаревшие значения - в основном это означает, что это означает, что чтение считается слишком ранним, поскольку кеш сохраняется согласованным; но чтение еще не должно быть перемещено.

Наконец, вы, похоже, думаете, что Java Memory Model (JMM) свойственна, в то время как основы в настоящее время довольно современны и похожи на блоки Ada, POSIX (в зависимости от интерпретации стандарта) и модель памяти C/С++. Возможно, вам захочется прочитать кулинарную книгу JSR-133, в которой объясняется, как JMM реализуется на существующих архитектурах: http://g.oswego.edu/dl/jmm/cookbook.html.

Ответ 3

Ответ будет заключаться в том, что большинство многопроцессоров являются кеш-когерентными, включая большие системы NUMA, которые почти? всегда являются ccNUMA.

Я думаю, вы несколько смущены относительно того, насколько когерентность кэша выполняется на практике. Во-первых, кэши могут быть когерентными/некогерентными в отношении нескольких других вещей в системе:

  • Устройства
  • (Память изменена) DMA
  • кэши данных и кэши команд
  • Кэши на других ядрах/процессорах (о которых идет речь)
  • ...

Что-то нужно сделать для поддержания согласованности. При работе с устройствами и DMA на архитектурах с некогерентными кэшами по отношению к DMA/устройствам вы либо обходите кеш (и, возможно, буфер записи), либо недействите/очищаете кеш вокруг операций, связанных с DMA/устройствами.

Аналогично, при динамическом создании кода вам может понадобиться очистить кеш команд.

Когда дело доходит до кэшей CPU, согласованность достигается с использованием некоторого протокола согласованности, такого как MESI, MOESI,... Эти протоколы определяют сообщения, отправляемые между кешами в ответ на определенные события (например: invalidate-запросы к другим кэшам когда изменена неэксклюзивная калина,...).

Хотя этого достаточно для поддержания (возможной) согласованности, он не гарантирует упорядочение или что изменения сразу видны другим ЦП. Тогда есть также буферы записи, которые задерживают запись.

Таким образом, каждая архитектура ЦП обеспечивает гарантии порядка (например, доступ до того, как упорядоченное хранилище не может быть переупорядочено после магазина) и/или предоставить инструкции (барьеры/ограждения памяти) для запроса таких гарантий. В конце концов, вход/выход из монитора не влечет за собой сброс кеша, но может повлечь за собой списание буфера записи и/или срыв ожидания ожидающих окончания чтения.

Ответ 4

кэши, к которым JVM имеет доступ, - это действительно только регистры CPU. так как их не так много, их промывка на выходе монитора не имеет большого значения.

EDIT: (в общем случае) кэши памяти не находятся под управлением JVM, JVM не может выбирать чтение/запись/очистку этих кешей, поэтому забудьте о них в этом обсуждении

Представьте, что каждый процессор имеет 1 000 000 регистров. JVM с радостью использует их для безумных быстрых вычислений - пока он не столкнется с входом/выходом монитора и должен сбросить 1 000 000 регистров на следующий уровень кэша.

если мы живем в этом мире, либо Java должна быть достаточно умна, чтобы анализировать, какие объекты не разделены (большинство объектов нет), либо он должен попросить программистов сделать это.

Модель памяти java - упрощенная модель программирования, которая позволяет средним программистам выполнять алгоритмы многопоточности. "упрощенным" я имею в виду, что во всем мире может быть 12 человек, которые действительно читают главу 17 JLS и действительно понимают ее.