Да, это потому, что x++
и x--
не являются атомами c операциями. Если одна из этих операций прервана, другой поток мог изменить значение x
, поэтому поток, выполняющий операцию увеличения или уменьшения, сохраняет результат, который вычисляется из устаревшего значения x
.
Вот возможное чередование, которое приводит к печати x=9
, x=8
, x=9
. В этом конкретном перемежении операции приращения в P1 и P2 начинаются с одного и того же значения x
, и поэтому они оба записывают один и тот же результат, так что x
эффективно увеличивается только один раз.
P1 P2 x
10
LD R0, x 10
DECR R0 10
ST R0, x 10→9
LD R0, x 9
DECR R0 9
ST R0, x 9→8
LD R0, x 8
LD R0, x 8
INCR R0 8
ST R0, x 8→9
INCR R0 9
ST R0, x 9→9
print 9
GOTO loop 9
LD R0, x 9
DECR R0 9
ST R0, x 8
print 8
GOTO loop
LD R0, x 8
INCR R0 8
ST R0, x 8→9
print 9
GOTO loop 9
Обратите внимание, что в этом чередовании тело l oop выполняется три раза (один раз в P1 и один раз в P2), а конечное значение x
не равно 10. Аналогичная последовательность может повторяться, и значение x
может оказаться сколь угодно низким. Симметрично, это могло бы в конечном итоге быть сколь угодно высоким.
Вот еще одно перемежение, где достигается 8 с одной итерацией в каждом потоке. В этом случае операция уменьшения в P2 фактически отменяет приращение в P2. С этим перемежением самый первый вывод - x=8
, за которым следует x=9
.
P1 P2 x
10
LD R0, x 10
DECR R0 10
ST R0, x 10→9
LD R0, x 9
DECR R0 9
LD R0, x 9
INCR R0 9
ST R0, x 9→10
ST R0, x 10→8
LD R0, x 8
print 8
GOTO loop
INCR R0 8
ST R0, x 8→9
print 9
GOTO loop 9
Вот еще одно перемежение, где вывод начинается с x=8
, x=7
, x=6
. Здесь все операции приращения оказываются эффективно отмененными одновременным уменьшением. Это может go навсегда.
P1 P2 x
10
LD R0, x 10
DECR R0 10
ST R0, x 10→9
LD R0, x 9
DECR R0 9
LD R0, x 9
INCR R0 9
ST R0, x 9→10
ST R0, x 10→8
LD R0, x 8
print 8
GOTO loop 8
LD R0, x 8
DECR R0 8
INCR R0 8
ST R0, x 8→9
ST R0, x 9→7
LD R0, x 7
print 7
GOTO loop 7
LD R0, x 7
INCR R0 7
ST R0, x 8
DECR R0 8
ST R0, x 8→6
print 6
GOTO loop 6