#java #concurrency
#java #параллелизм
Вопрос:
Я пытаюсь понять, как работает теория взаимного исключения.
В нем говорится
Когда такой связанный список используется совместно несколькими потоками выполнения, два потока выполнения могут попытаться удалить два разных узла одновременно, один поток выполнения изменяет следующий указатель узла i-1
, чтобы указать на узел i 1
, в то время как другой поток выполнения изменяет следующий указатель узла i
, чтобы указать на узел i 2
.
Здесь запутался:
Хотя обе операции удаления завершаются успешно, желаемое состояние связанного списка не достигается: узел i 1 остается в списке, потому что следующий указатель узла i-1 указывает на узел i 1.
the desired state of the linked list is not achieved
Могу я узнать, что он пытается сказать "because the next pointer of node i-1 points to node i 1."
? Не мог понять.
Комментарии:
1. Пожалуйста, уточните свой вопрос. 1) Насколько я вижу, суть вопроса вообще не о взаимном исключении. 2) Описание, похоже, связано с конкретной реализацией «remove», но вы не показали нам код этой реализации.
Ответ №1:
Рассмотрим связанный список
A -> B -> C -> D
Вы говорите потоку 1 «Эй, удалите B для меня, хорошо?». В то же время вы говорите потоку 2: «Эй, ты можешь удалить C для меня?».
Затем одновременно происходит следующее:
- Поток 1 думает: «Хорошо, я хочу удалить B. Это означает, что я должен указать на C вместо B. «
- Поток 2 думает: «Хорошо, я хочу удалить C. Это означает, что я должен указать B на D вместо C. «
Два потока разделены; они не знают, что делает другой. Таким образом, они оба считают, что их аргументы имеют смысл. И они это делают, но только тогда, когда никто другой не изменяет список одновременно. Результат выглядит следующим образом:
A -> C -> D
B -^
A больше не указывает на B; вместо этого он указывает на C. Аналогично, B больше не указывает на C; вместо этого он указывает на D .
… и поскольку B больше недоступен, он будет собран как мусор, оставляя это:
A -> C -> D
Мы сказали одному потоку удалить B, а другому потоку удалить C. B исчез, но C все еще в списке. Это не то, что мы ожидали; мы ожидали, что останутся только A и D.
Это очень простой пример того, как могут произойти ужасные ошибки, когда несколько потоков одновременно изменяют одни и те же данные. Вам нужно либо использовать сложные приемы, чтобы заставить его работать, либо использовать «взаимное исключение», то есть ограничивать изменения списка только одним потоком за раз.
Комментарии:
1. Почему C все еще в списке?
Ответ №2:
В приведенном вами примере, который, я полагаю, изложен в Википедии, отсутствуют некоторые важные детали.
- У нас есть общий ресурс
(i-1)->(i)->(i 1)->(i 2)
- У нас есть два потока выполнения, давайте вызовем их
T1
иT2
одновременно получим доступ к связанному списку как к общему ресурсу. T1
удаляет узел(i)
одновременноT2
с удалением узла(i 1)
- Результирующий список был
(i-1) -> (i 2)
бы, если бы мы выполнили эти шаги последовательно - Вместо этого мы получаем :
(i-1) -> (i 1) -> (i 2)
Взаимное исключение относится к тому факту, что один поток выполнения никогда не должен входить в свою критическую секцию в то же время, когда другой параллельный поток выполнения входит в свою собственную критическую секцию. В приведенном выше примере нам нужно было бы предотвратить одновременное изменение одного и того же списка обоими потоками, используя какой-то примитив синхронизации.