Re[5]: Двойная блокировка переключатель
От: Sinclair Россия https://github.com/evilguest/
Дата: 23.09.15 04:11
Оценка: +1
Здравствуйте, igor-booch, Вы писали:

IB>опишу задачу по другому, конкретно что нужно:


IB>Есть два ресурса (объекта) A и B.

IB>Есть потоки которые всегда захватывают сначала A, а потом B. Это потоки типа N.
IB>Есть потоки которые захватывают только B. Это потоки типа M.
IB>Если пользоваться обычным обычным Monitor'ом, то получается следующее.

IB>1) Поток I типа N захватывает ресурс A.

IB>2) Теперь потоку I требуется переключиться на блокировку ресурса B. Для этого
IB> 2.1) Поток I освобождает ресурс А
IB> 2.2) Поток I захватывает ресурс B

IB>Существует вероятность, что между пунктами 2.1 и 2.2 вклинится другой поток типа N и также захватит сначала A, потом B. Это недопустимо. Освобождение и захват должны быть атомарной операцией.

IB>Кажется что можно поменять пункты 2.1 и 2.2 местами, то есть сначала захватывать B, а потом освобождать A. Но на сцену выходят потоки типа M. Поток типа M может захватить B до захвата потоком I блокировки B и тогда A не освободится до освобождения потоком типа M блокировки B, что недопустимо. Допустимо, если поток I переключится на блокировку B, и подождет пока её освободит поток типа M. При этом во время ожидания блокировка A будет свободна.
Выделенные требования несовместимы. Следите за руками:
1. Поток N1 захватил А
2. Поток М1 захватил B
3. Поток N1 пытается сконвертировать А в В. По вашему требованию, он уже отпустил А и теперь стоит в ожидании B
4. Поток N2 захватывает А
5. Поток N2 пытается сконвертировать А в В.
6. Поток M1 отпускает B.
В этот момент у потоков N1 и N2 равные шансы захватить B. Это означает, что с вероятностью 50% произойдёт сценарий вклинивания N2 внутрь транзакции, выполняемой N1, что по вашему второму требованию запрещено.

IB>Я вижу пока только один способ, также пользуемся обычным обычным Monitor'ом но по-другому


IB>1) Поток I типа N захватывает ресурс A.

IB>2) Теперь потоку I требуется переключиться на блокировку ресурса B. Для этого
IB> 2.1) Поток I запускает дополнительный поток III. В этом потоке сначала захватывается B, потом выполняется код, который поток I хотел выполнить после переключения на блокировку ресурса B.
IB> 2.2) Поток I освобождает ресурс A
IB> 2.3) Поток I ждёт завершения потока III (.Join)
Вы же понимаете, что порядок выполнения 2.1 и 2.2 ничем не гарантирован? Т.е. поток I может освободить ресурс А задолго до того, как III захватит B. Поэтому функционально это решение эквивалентно неатомарному освобождению А, а затем захвату B.
IB>Хочется без создания дополнительных потоков. Может что-то с низкоуровневым примитивами синхронизации можно что-то замутить, может ReaderWriterLock как-то использовать
Я всё ещё не понимаю природы ваших ограничений. На первый взгляд, задача решается в том случае, если доступ к B будет рулиться не монитором, а очередью — чтобы гарантировать, что потоки получают доступ к B в том же порядке, как они получали доступ к А.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.