Этот ответ основан на ответе Джима и связанных с ним комментариях.
Если проблема связана с отсутствием ключевого слова volatile
, потоки должны сразу же зайти в тупик, они никогда не смогутувеличить счетчик.- sarva
Это неверно, нет способа гарантировать, что записанное значение будет распространяться на другие потоки.
Кстати, реализация LockTwo
в ArtofMPимеет ключевое слово volatile
, связанное с victim
, но исправления требуют, чтобы это ключевое слово было удалено.- sarva
Это только потому, что согласованность с другими алгоритмами представлена в той же главе.В прагме 2.3.1 говорится, что victim
, label
и т. Д. Должны быть объявлены на практике volatile
, но тогда victim
объявляется volatile
на рисунке 2.5 в любом случае.
Если я добавлю ключевое слово volatile
к victim
, то в самом конце возникает тупик, когда один поток завершает выполнение, увеличивая счетчик до 100, а другой поток ожидает в while(victim == i) {}
без изменения значенияжертвы.- Сарва
Это поведение, которое вы хотите.Рассмотрим однопотоковую программу, поэтому следующие строки из вашей программы не имеют смысла:
victim = i;
while (victim == i) {}
Без дополнительного потока это будет бесконечный цикл.
Мы можем получитьпо существу эквивалентная ситуация в двухпоточной программе, когда только один из потоков пытается получить блокировку (т. е. вызвать метод lock
).
Если оба потока вызывают метод lock
, мы получаемповедение, которое вы наблюдали, когда в конце возникает тупик:
- Первый поток вызывает
lock
и устанавливает victim
в 0 и начинает цикл - Второй поток вызывает
lock
и устанавливает victim
в 1 и начинает цикл - Первый поток видит, что
victim
теперь равен 1, и входит в критическую секцию - Если первый поток никогда не вызывает
lock
метод снова, второй поток будет застревать в цикле навсегда, ожидая, пока victim
станет 1
Таким образом, (в некотором смысле) последний вызов не завершится, если оба потока вызовутlock
метод мюНесколько раз каждый.