Можно ли описать результат JCStress как результат кэширования, а не переупорядочения?
Я изменил один из примеров JCStress :
@JCStressTest
@Outcome(id = "0, 0", expect = ACCEPTABLE, desc = "Doing both reads early.")
@Outcome(id = "1, 1", expect = ACCEPTABLE, desc = "Doing both reads late.")
@Outcome(id = "1, 0", expect = ACCEPTABLE, desc = "First is visible but not second.")
@Outcome(id = "0, 1", expect = ACCEPTABLE_INTERESTING, desc = "Second is visible but not first.")
@State
public class Reordering {
int first;
int second;
@Actor
public void actor1() {
first = 1;
second = 1;
}
@Actor
public void actor2(II_Result r) {
r.r2 = second;
r.r1 = first;
}
}
что дало мне следующий результат:
Приемлемые результаты легко понять, но у меня есть несколько вопросов относительно интересного результата . Насколько я понял, JVM может оптимизировать код и изменить порядок инструкций, что означает, что первую функцию можно примерно перевести так:
public void actor1() {
second = 1;
first = 1;
}
что могло бы объяснить, почему был достигнут интересный результат. Мой вопрос: возможно ли, что интересный результат был достигнут не за счет переупорядочения кода, выполненного JVM, а за счет «кэширования»first
и не делать его видимым для запущенного потокаactor2
метод, поскольку поле не было нестабильным? Под кэшированием я говорю о сохранении его в регистре/буфере хранения ЦП и о том, чтобы сделать его невидимым для другого потока.
1 ответ
На X86 магазины нельзя переупорядочить с другими хранилищами, а загрузки нельзя переупорядочить с другими загрузками (переупорядочить можно только более старый магазин и новую загрузку на другой адрес). Так что если компилятор не напутает порядок, то на X86 это не может не сработать. Это связано с сильной моделью памяти X86: TSO (Total Store Order).
Однако если вы выберете процессор с более слабой моделью памяти, например ARM или RISC-V, такое переупорядочение может произойти.