Re[9]: volatile
От: remark Россия http://www.1024cores.net/
Дата: 25.09.09 22:31
Оценка: 5 (2)
Здравствуйте, Golovach Ivan, Вы писали:

SZ>>Сорри, поторопился слегка На самом деле предыдущие виртуальные машины могли реордерить volatile и non-volatile (т.е. если int не volatile, а bool — volatile, тогда код не работает). Две volatile переменные запрещалось реордерить и раньше. В новых VM (5.0), грубо говоря, запрещен также реордеринг volatile и non-volatile переменных. Т.е. после до присваивания чего-либо volatile переменной компилятор обязан сделать все присвоения non-volatile переменных. В новых VM (5.0), грубо говоря, запрещен также реордеринг volatile и non-volatile переменных.


GI>Реордеринг volalile и не-volalile в некоторых случаях разрешен, а в некоторых нет.

GI>Об этом проще прочитать в статье Doug Lea "The JSR-133 Cookbook for Compiler Writers" http://gee.cs.oswego.edu/dl/jmm/cookbook.html в главе 'Volatiles and Monitors'.


Это не тот документ, куда надо смотреть Java программисту, программисту надо смотреть в спецификацию языка. Тут есть 2 уровня, первый — формальная спецификация для программиста, второй — реализация. Связующее звено между ними — это обеспечение *видимости* выполнения спецификации. Это важно понимать, что есть специфицированное поведение, а что есть — деталь реализации.
Например, если в программе записано деление 2 переменных, то с т.з. программиста это только деление и ничего больше. При генерации же машинного кода это деление может быть представлено делением, умножением, сдвигом, вычислением по таблице, вычисление с частными случаями и т.д. Или, например, вычисления без побочных эффектов могут быть полностью устранены компилятором. Т.е. формально компилятор не делает того, что он него просит программист, но это нормально, пока обеспечивается *видимость* выполнения спецификации.
Обратите внимание на выделенное:

This table is not itself the JMM specification; it is just a useful way of viewing its main consequences for compilers and runtime systems.

И дальше:

So, for example, the "No" in cell [Normal Store, Volatile Store] says that a non-volatile store cannot be reordered with ANY subsequent volatile store; at least any that can make a difference in multithreaded program semantics.

Т.е. компилятор может и не переупорядочивать обычные обращения и volatile обращения. Но может и переупорядочивать, потому что это не влияет на видимое поведение, и у программиста нет никаких средств отличить 2 поведения. Последний абзац говорит даже больше — на самом деле компилятор может делать *любые* переупорядочивания и оптимизации, *пока* они не меняют семантики многопоточной программы.
Например для такого кода:
volatile int X;
X = 1;
X = 2;
Компилятор может убрать строчку ”X = 1;”, т.е. программа никаким образом не сможет это отличить.
Или, например, если компилятор делает escape анализ и может определить, что volatile переменная локальна для потока, то он может трактовать её как обычную переменную и делать с ней любые переупорядочивания.
Т.е., грубо говоря, на уровне реализации с volatile переменными может происходить вообще что угодно. А упомянутая таблица есть лишь наиболее разумное и простое отображение JMM на расслабленную модель памяти (SPARC RMO) для общих случаев.

Т.о. ответ на вопрос могут ли обычные обращения к памяти переупорядочиваться с volatile для программиста — нет, не могут. Другой взгляд на это — некоторые переупорядочивания не возможны, а другие абсолютно не интересны. Просто судить о семантике программы на основе последовательно-консистентной (sequentially consistent) модели памяти (т.е. без переупорядочиваний) на порядок проще, чем на основе расслабленной модели (т.е. с переупорядочиваниями). А это как раз и есть основная идея, стоящая за Java volatile, — обеспечение последовательной консистентности, т.е. отсутствие любых переупорядочиваний, т.е. простота (обмен скорости на простоту использования).

Однако для Java тут есть ещё небольшая оговорка, которая называется, non properly synchronized programs (некорректно синхронизированные программы). Они могут увидеть практически любые переупорядочивания и другие интересные вещи. Но их семантика не особо интересна, т.к. фактически они официально обозваны «плохими» программами, в них содержатся гонки, и единственное намерение по поводу их функционирования — это предотвращение компромитации безопасности и падения JVM (для стороннего «подозрительного» кода). Такая же ситуация и для C#. А, например, для С++ нет проблемы выполнения «подозрительного» кода, поэтому С++ просто полностью запрещает некорректно синхронизированные программы, не давая абсолютно никаких гарантий по поводу их функционирования.

Ещё раз — с т.з. программиста Java volatile обеспечивают последовательную консистентность и не допускают никаких переупорядочиваний. Это то, чем надо руководствоваться; всё остальное — детали реализации.


1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
jmm volatile
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.