Причинность в JMM кажется самой запутанной частью этого. У меня есть несколько вопросов, касающихся причинности JMM, и разрешено поведение в параллельных программах.
Как я понимаю, текущий JMM всегда запрещает циклы причинности. (Правильно?)
Теперь, согласно документу JSR-133, страница 24, Рис .16, мы имеем пример, где:
Изначально x = y = 0
Тема 1:
r3 = x;
if (r3 == 0)
x = 42;
r1 = x;
y = r1;
Тема 2:
r2 = y;
x = r2;
Интуитивно, r1 = r2 = r3 = 42
представляется невозможным. Однако это не только упоминается как возможно, но и "разрешено" в JMM.
Для возможности объяснения из документа, которые я не понимаю, это:
Компилятор может определить, что единственными значениями, когда-либо назначенными
x
, являются: 0 и 42. Из этого компилятор мог бы сделать вывод, что в точке где мы выполняемr1 = x
, либо мы только что выполнили запись 42 вx
, или мы только что прочиталиx
и увидели значение 42. В любом случае это будет легальным для чтенияx
, чтобы увидеть значение 42. Затем он может изменитьr1 = x
наr1 = 42
; это позволило бы преобразоватьy = r1
вy = 42
и выполнить ранее, в результате чего поведение в вопросе. В этом случае запись вy
выполняется первый.
Мой вопрос в том, что это за оптимизация компилятора? (Я компилятор-невежда.) Поскольку 42 записывается только условно, когда оператор if
выполняется, как компилятор может решить записать с помощью x
?
Во-вторых, даже если компилятор выполняет эту спекулятивную оптимизацию и совершает y = 42
и
то, наконец, делает r3 = 42
, не является ли это нарушением цикла причинности, так как теперь нет разницы в причинах и следствиях?
На самом деле есть один пример в том же документе (стр. 15, рис. 7), где подобный причинный цикл упоминается как неприемлемый.
Итак, почему этот порядок выполнения является законным в JMM?