Не совсем понятно, что Вы имеете ввиду под "как раз это".
Я так понял, что Вы написали, что у процессора, соответсвующего strict consistency, операции записи должны выполняться мгновенно (в смысле физического времени) и что это невозможно физически.
На мой взгляд, приведённая Вами цитата не требует от процессора мгновенных(в смысле физического времени) операций записи, и что процессор, соответсвующий strict consistency, создать вполне возможно.
если бы в теории мы имели strict consistency модель, то операции записи должны были бы завершаться мгновенно ... Но это не возможно просто физически.
И потом приводите такую цитату:
The sequential consistency is weaker than strict consistency, which requires a read from a location to return the value of the last write to that location; strict consistency demands that operations be seen in the order in which they were actually issued.
Но эта цитата не утверждает, что операции должны завершаться мгновенно. Она утверждает, что, начиная с момента времени, когда операция становится выполненной, она должна стать видимой другим процессорам. Но при этом выполнение операции вполне может занимать какое-то время.
В Вашем примере если write(x,1) становится выполненным в момент времени t, то любой read(x) начатый позже t должен возвратить 1 или более позднюю запись.
Пример процессора, которые мог бы реализовать это физически:
с когерентным кэшем без Invalidation Queue и Store Buffer
следующая инструкция начинает выполняться только после того, как выполнилась текущая инструкция
write становится выполненным когда означение записано в cache line
read становится выполненным когда значение прочитано из кэша
Хорошо, что в итоге разобрались. Похожее обсуждение было недавно на stackoverflow. Видимо подобные вопросы продолжат возникать у java-программистов и в будущем. И возможно эта ветка комментариев кому-нибудь из них поможет разобраться.
Кстати, даже если эта цитата действительно означает eventual visibility для volatile, то это будет работать только в data-race-free программах (ведь java гарантирует Sequential consistency только в таких случаях).
Как мы знаем, программа data-race-free только если в ней вообще нет data race. В итоге, стоит только добавить в java-приложение какой-нибудь тестовый класс с data race внутри, и гарантия eventual visibility для volatile исчезает сразу во всех классах нашего приложения.
Кроме того, в String.hashCode() чтение и запись поля hash - это data race. Получается тем, кто в java хочет eventual visibility для volatile, нельзя использовать строки.
По-моему, immediately visible to every thread тут означает, что чтение переменной всегда возвращает последнюю с точки зрения execution order запись в эту переменную. При этом этот так называемый "execution order" при Sequential consistency не подразумевает привязки к реальному времени исполнения инструкций. И поэтому я не думаю, что приведённая цитата гарантирует, что volatile записи обязательно становятся видимыми в других потокам.
Опять же, насколько я понимаю, в SC не ограничена задержка, с которой запись в одном потоке становится видимой другим потокам. И поэтому, например, x=3 из T2 может стать видимым в T1, допустим, через год - и это не нарушит SC.
в остальной JMM реальное время не соблюдается и никакого immediately visible to every thread нет.
В частности, в статье выше упоминалось про happens-before:
Давайте сразу проясним один момент: нет, happens-before не означает, что инструкции будут действительно выполняться в таком порядке. Если переупорядочивание инструкций все равно приводит к консистентному результату, то такое переупорядочивание инструкций не запрещено.
Если инструкции переупорядочиваются, значит в случае с happens-before привязки к реальному времени исполнения инструкций нет — важно лишь чтобы результат был таким же.
Логично предположить, что в и случае SC - инструкции внутри, к примеру, synchronized{} блоков также разрешено переупорядочивать. Соответсвенно эти инструкции также не будут выполняться по одной и сразу становиться immediately visible to every thread.
Также было бы странно, если бы eventual visibility гарантировалась только для SC (т.е. только для data-race-free программ): ведь самые заоптимизированные по многопоточной производительности алгоритмы (типа содержимого java.util.concurrent) частенько используют всякие хаки типа кода с data race-ами. Было бы странно, если бы именно таким алгоритмам не гарантировалась eventual visibility.
Итак, ядра действительно всегда видят актуальное значение, но только кроме короткого временного окна после записи. Другими словами, нам гарантируется eventual visibility изменений.
Исправить этот пример можно пометив переменную как volatile — только в этом случае нам гарантируется eventual visibility изменений.
Любопытный факт: cтрого говоря, в java нет гарантий того, что volatile запись должна в течение какого-то времени стать видимой другим потокам.
В итоге формально допустима volatile запись, которая никогда не станет видимой другим потокам. Более того, допустима реализация JVM, в которой все записи никогда не видны другим потокам.
Конечно же, java-программисты надеются, что в используемых на практике реализациях JVM таких "оптимизаций" нет.
А вот в c++ eventual visibility гарантируется:
18 An implementation should ensure that the last value (in modification order) assigned by an atomic or synchronization operation will become visible to all other threads in a finite period of time.
11 Implementations should make atomic stores visible to atomic loads within a reasonable amount of time.
Возможно, из описания не совсем понятно, что этот код делает.
Можно попробовать объяснить вот так:
Код:
public class MemoryReorderingExample {
private int x;
private int y;
public void T1() {
x = 1;
int r1 = y;
}
public void T2() {
y = 1;
int r2 = x;
}
}
Тут T1() выполняется в первом потоке, T2() - во втором.
Обычно люди, незнакомые с JMM, полагают, что в таком случае действия в каждом потоке выполняются последовательно. И в итоге, они считают, что есть всего 4 варианта того, в каком порядке выполняются действия потоков:
x = y = 0;
T1 | T2 T1 | T2
-------------------------- --------------------------
x = 1; | x = 1; |
int r1 = y; | | y = 1;
| y = 1; int r1 = y; |
| int r2 = x; | int r2 = x;
T1 | T2 T1 | T2
-------------------------- --------------------------
| y = 1; x = 1; |
x = 1; | | y = 1;
int r1 = y; | | int r2 = x;
| int r2 = x; int r1 = y; |
Как видите, во всех четырёх случаях первым всегда идёт либо x = 1; либо y = 1;, а значит результата (r1==0, r2==2) быть не должно.
А в JMM такой результат допустим. Значит описанный выше "интуитивный" подход не работает в java, и программистам нужно разбираться с happens-before, volatile и остальной JMM.
Я, почему-то, наоборот, слово "имплементация" встречал в основном в политическо-юридическом контексте. А в программировании и в IT - я в основном встречал "реализация": "реализация алгоритма на языке java", "реализация наследуемых абстрактных методов в дочернем классе" и т.п.
Кстати, определение термина имплементация в википедии использует термин "реализация":
Имплементация (программирование) — программная или аппаратная реализация какого-либо протокола, алгоритма, технологии
Прекрасная статья. У Вас действительно хорошо получается объяснять понятным языком: читая статью я несколько раз ловил себя на мысли, что сам я не смог бы объяснить данный момент проще и понятней.
В качестве конструктивной критики: боюсь что таких слов "имплементация" и "консистентность" в русском языке нет. Я так понимаю это implementation и consistency написанные русскими буквами. Это не критично, но всё-таки немного режет глаз. Как вариант, эти слова можно заменить на "реализация" и "согласованность/соответсвие", или даже просто использовать английские термины.
Также я заметил вот такую ошибку в тексте:
Shared — линия кэша актуальна и эквивалентна памяти. Когда значение из памяти первые загружается в кэш, то линия кэша устанавливается именно в shared состояние.
Не совсем понятно, что Вы имеете ввиду под "как раз это".
Я так понял, что Вы написали, что у процессора, соответсвующего strict consistency, операции записи должны выполняться мгновенно (в смысле физического времени) и что это невозможно физически.
На мой взгляд, приведённая Вами цитата не требует от процессора мгновенных(в смысле физического времени) операций записи, и что процессор, соответсвующий strict consistency, создать вполне возможно.
В коментарии выше ошибка: вариантов 6, а не четыре.
Небольшое замечание по поводу strict consistency.
Вы пишите:
И потом приводите такую цитату:
Но эта цитата не утверждает, что операции должны завершаться мгновенно.
Она утверждает, что, начиная с момента времени, когда операция становится выполненной, она должна стать видимой другим процессорам.
Но при этом выполнение операции вполне может занимать какое-то время.
В Вашем примере если
write(x,1)становится выполненным в момент времениt, то любойread(x)начатый позжеtдолжен возвратить1или более позднюю запись.Пример процессора, которые мог бы реализовать это физически:
с когерентным кэшем без Invalidation Queue и Store Buffer
следующая инструкция начинает выполняться только после того, как выполнилась текущая инструкция
writeстановится выполненным когда означение записано в cache linereadстановится выполненным когда значение прочитано из кэшаХорошо, что в итоге разобрались.
Похожее обсуждение было недавно на stackoverflow.
Видимо подобные вопросы продолжат возникать у java-программистов и в будущем.
И возможно эта ветка комментариев кому-нибудь из них поможет разобраться.
Кстати, даже если эта цитата действительно означает eventual visibility для
volatile, то это будет работать только в data-race-free программах (ведь java гарантирует Sequential consistency только в таких случаях).Как мы знаем, программа data-race-free только если в ней вообще нет data race.
В итоге, стоит только добавить в java-приложение какой-нибудь тестовый класс с data race внутри, и гарантия eventual visibility для
volatileисчезает сразу во всех классах нашего приложения.Кроме того, в
String.hashCode()чтение и запись поляhash- это data race.Получается тем, кто в java хочет eventual visibility для
volatile, нельзя использовать строки.По-моему, immediately visible to every thread тут означает, что чтение переменной всегда возвращает последнюю с точки зрения execution order запись в эту переменную.
При этом этот так называемый "execution order" при Sequential consistency не подразумевает привязки к реальному времени исполнения инструкций.
И поэтому я не думаю, что приведённая цитата гарантирует, что
volatileзаписи обязательно становятся видимыми в других потокам.Почему я так считаю:
Sequential consistency (SC) (в отличии от Strict consistency) обычно не подразумевает, что действия становятся видимы мгновенно.
При этом в SC:
есть общий для всех потоков порядок чтений и записей (т.н. execution order)
program order чтений и записей каждого потока соблюдается в execution order
упорядоченность операций по реальному времени исполнения в execution order соблюдать не требуется
Пример.
Реальное время выполнения инструкций процессором:
Возможные execution order:
x=1 -> y=2 -> x=3x=1 -> x=3 -> y=2x=3 -> x=1 -> y=2Опять же, насколько я понимаю, в SC не ограничена задержка, с которой запись в одном потоке становится видимой другим потокам.
И поэтому, например,
x=3из T2 может стать видимым в T1, допустим, через год - и это не нарушит SC.в остальной JMM реальное время не соблюдается и никакого immediately visible to every thread нет.
В частности, в статье выше упоминалось про happens-before:
Если инструкции переупорядочиваются, значит в случае с happens-before привязки к реальному времени исполнения инструкций нет — важно лишь чтобы результат был таким же.
Логично предположить, что в и случае SC - инструкции внутри, к примеру,
synchronized{}блоков также разрешено переупорядочивать.Соответсвенно эти инструкции также не будут выполняться по одной и сразу становиться immediately visible to every thread.
Также было бы странно, если бы eventual visibility гарантировалась только для SC (т.е. только для data-race-free программ): ведь самые заоптимизированные по многопоточной производительности алгоритмы (типа содержимого java.util.concurrent) частенько используют всякие хаки типа кода с data race-ами.
Было бы странно, если бы именно таким алгоритмам не гарантировалась eventual visibility.
Любопытный факт: cтрого говоря, в java нет гарантий того, что
volatileзапись должна в течение какого-то времени стать видимой другим потокам.В итоге формально допустима
volatileзапись, которая никогда не станет видимой другим потокам.Более того, допустима реализация JVM, в которой все записи никогда не видны другим потокам.
Конечно же, java-программисты надеются, что в используемых на практике реализациях JVM таких "оптимизаций" нет.
А вот в c++ eventual visibility гарантируется:
Согласен.
Код в статье правильный: вот этот же пример в JCStress.
Возможно, из описания не совсем понятно, что этот код делает.
Можно попробовать объяснить вот так:
Код:
Тут
T1()выполняется в первом потоке,T2()- во втором.Обычно люди, незнакомые с JMM, полагают, что в таком случае действия в каждом потоке выполняются последовательно.
И в итоге, они считают, что есть всего 4 варианта того, в каком порядке выполняются действия потоков:
Как видите, во всех четырёх случаях первым всегда идёт либо
x = 1;либоy = 1;, а значит результата(r1==0, r2==2)быть не должно.А в JMM такой результат допустим.
Значит описанный выше "интуитивный" подход не работает в java, и программистам нужно разбираться с
happens-before,volatileи остальной JMM.Понятно.
Я, почему-то, наоборот, слово "имплементация" встречал в основном в политическо-юридическом контексте.
А в программировании и в IT - я в основном встречал "реализация": "реализация алгоритма на языке java", "реализация наследуемых абстрактных методов в дочернем классе" и т.п.
Кстати, определение термина имплементация в википедии использует термин "реализация":
Комментарий удалён
Прекрасная статья.
У Вас действительно хорошо получается объяснять понятным языком: читая статью я несколько раз ловил себя на мысли, что сам я не смог бы объяснить данный момент проще и понятней.
В качестве конструктивной критики: боюсь что таких слов "имплементация" и "консистентность" в русском языке нет. Я так понимаю это implementation и consistency написанные русскими буквами.
Это не критично, но всё-таки немного режет глаз.
Как вариант, эти слова можно заменить на "реализация" и "согласованность/соответсвие", или даже просто использовать английские термины.
Также я заметил вот такую ошибку в тексте:
Судя по Table 1.1 в статье о MESI на вики, в этом случае состояние будет Exclusive.