Двойная блокировка переключатель
От: igor-booch Россия  
Дата: 16.09.15 13:28
Оценка:
Блокировка эксклюзивно блокирует два ресурса.
Но не два одновременно, а напротив не допускает одновременного захвата обоих ресурсов.
Захвачен может быть только один ресурс, либо оба ресурса должны быть свободны.
Освобождение захваченного ресурса, происходит при захвате свободного ресурса.

Например, блокировка работает с 2-ми ресурсами A и B.

Предположим захвачен ресурс B
При захвате А, освобождается B
При освобождении А, B не захватывается, оба ресурса становятся свободными

И наоборот
Предположим захвачен ресурс A
При захвате B, освобождается A
При освобождении B, A не захватывается, оба ресурса становятся свободными

Не обязательно чтобы работало наоборот, мне достаточно чтобы работало только в прямом направлении (то есть ресурсы асимметричны), но если будет работать и наоборот (то есть ресурсы симметричны), то это не помешает.

Если оба ресурса свободны, то захват одного из них не к чему не приводит.

Операция "захват и освобождение" должна быть атомарной (потокобезопасной)

Примерный код

Resource a = new Resource();
Resource b = new Resource();

using (DoubleLockSwitch dls = new DoubleLockSwitch(a, b)
{
    dls.Lock(a);
    //work
    if (condition)
    {
        dls.Lock(b);
        // work
    }
    //work
}


Есть ли такая блокировка в готовом виде? Можно ли её реализовать с помощью других примитивов синхронизации?
Отвечайте на это сообщение, только если у Вас хорошее настроение и в Вашем ответе планируются только конструктивные вопросы и замечания
http://rsdn.ru/Info/rules.xml
Отредактировано 16.09.2015 14:35 igor-booch . Предыдущая версия . Еще …
Отредактировано 16.09.2015 14:05 igor-booch . Предыдущая версия .
Отредактировано 16.09.2015 13:51 igor-booch . Предыдущая версия .
Отредактировано 16.09.2015 13:51 igor-booch . Предыдущая версия .
Отредактировано 16.09.2015 13:47 igor-booch . Предыдущая версия .
Отредактировано 16.09.2015 13:44 igor-booch . Предыдущая версия .
Отредактировано 16.09.2015 13:41 igor-booch . Предыдущая версия .
Отредактировано 16.09.2015 13:39 igor-booch . Предыдущая версия .
Re: Двойная блокировка переключатель
От: Sinclair Россия https://github.com/evilguest/
Дата: 17.09.15 06:28
Оценка: 6 (1) +1
Здравствуйте, igor-booch, Вы писали:

IB>Блокировка эксклюзивно блокирует два ресурса.

IB>Но не два одновременно, а напротив не допускает одновременного захвата обоих ресурсов.
IB>Захвачен может быть только один ресурс, либо оба ресурса должны быть свободны.
IB>Освобождение захваченного ресурса, происходит при захвате свободного ресурса.

IB>Например, блокировка работает с 2-ми ресурсами A и B.


IB>Предположим захвачен ресурс B

IB>При захвате А, освобождается B
IB>При освобождении А, B не захватывается, оба ресурса становятся свободными

IB>И наоборот

IB>Предположим захвачен ресурс A
IB>При захвате B, освобождается A
IB>При освобождении B, A не захватывается, оба ресурса становятся свободными
Непонятно. Вы описали поведение только одного потока. Что должен наблюдать второй поток? Предположим, потоком I захвачена блокировка A.
Поток II пытается захватить блокировку B — что получает? Встаёт в ожидании; получает fail; успешно захватывает?
Если встаёт в ожидании, то вам не нужно иметь две блокировки, достаточно одной A+B. Если успешно захватывает, то в вашем коде — баг: как только поток I попробует захватить блокировку B, он встанет в ожидании.
Если поток II попробует вместо освобождения B захватить A, то вы поймаете deadlock.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Двойная блокировка переключатель
От: igor-booch Россия  
Дата: 20.09.15 13:06
Оценка:
S>Непонятно. Вы описали поведение только одного потока. Что должен наблюдать второй поток? Предположим, потоком I захвачена блокировка A.
S>Поток II пытается захватить блокировку B — что получает? Встаёт в ожидании; получает fail; успешно захватывает?
S>Если встаёт в ожидании, то вам не нужно иметь две блокировки, достаточно одной A+B. Если успешно захватывает, то в вашем коде — баг: как только поток I попробует захватить блокировку B, он встанет в ожидании.
fail. В моем коде все потоки сначала захватывают блокировку А потом B.

S>Если поток II попробует вместо освобождения B захватить A, то вы поймаете deadlock.

не понял, почему поймаю deadlock? Если исходить из того, что
S>Предположим, потоком I захвачена блокировка A.
То если поток II пробует захватить A, то он встаёт в ожидание.
Может я неправильно понял смысл "вместо освобождения B". Если их убрать смысл не поменяется. Что значит "вместо"?
Отвечайте на это сообщение, только если у Вас хорошее настроение и в Вашем ответе планируются только конструктивные вопросы и замечания
http://rsdn.ru/Info/rules.xml
Отредактировано 20.09.2015 13:08 igor-booch . Предыдущая версия . Еще …
Отредактировано 20.09.2015 13:07 igor-booch . Предыдущая версия .
Re[3]: Двойная блокировка переключатель
От: Sinclair Россия https://github.com/evilguest/
Дата: 21.09.15 06:01
Оценка: +1
Здравствуйте, igor-booch, Вы писали:

S>>Непонятно. Вы описали поведение только одного потока. Что должен наблюдать второй поток? Предположим, потоком I захвачена блокировка A.

S>>Поток II пытается захватить блокировку B — что получает? Встаёт в ожидании; получает fail; успешно захватывает?
S>>Если встаёт в ожидании, то вам не нужно иметь две блокировки, достаточно одной A+B. Если успешно захватывает, то в вашем коде — баг: как только поток I попробует захватить блокировку B, он встанет в ожидании.
IB>fail. В моем коде все потоки сначала захватывают блокировку А потом B.
Зачем тогда вам вообще такая "двойная блокировка"? Почему вам недостаточно иметь A+B?

S>>Если поток II попробует вместо освобождения B захватить A, то вы поймаете deadlock.

IB>не понял, почему поймаю deadlock?
Потому, что поток II будет стоять в ожидании освобождения A. А оно случится только тогда, когда поток I успешно захватит B, что невозможно, потому что его уже занял поток II.
S>>Предположим, потоком I захвачена блокировка A.
IB>То если поток II пробует захватить A, то он встаёт в ожидание.
IB>Может я неправильно понял смысл "вместо освобождения B". Если их убрать смысл не поменяется. Что значит "вместо"?
Это значит, что в вашей системе у владельца блокировки B возможно всего два действия: либо отпустить B, либо сконвертировать блокировку B в A.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: Двойная блокировка переключатель
От: koodeer  
Дата: 21.09.15 17:37
Оценка: 6 (1)
Здравствуйте, igor-booch.

Может, я немножко не по теме влезу, однако хочу упомянуть одну статью: Advanced Techniques To Avoid And Detect Deadlocks In .NET Apps, by Joe Duffy. Была опубликована в журнале MSDN Magazine, потом мелкософт удалил онлайн-материалы и взамен предлагает скачивать журналы в формате chm. Взять можно здесь — April 2006. В ней автор приводит (в статье есть ссылка на скачку самораспаковывающегося архива с исходниками) класс LeveledLock, применение которого контролирует порядок взятия блокировок на разных ресурсах. Что позволит избежать дедлоков, о которых написал Sinclair.
Re[4]: Двойная блокировка переключатель
От: igor-booch Россия  
Дата: 22.09.15 13:03
Оценка:
опишу задачу по другому, конкретно что нужно:

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

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

Существует вероятность, что между пунктами 2.1 и 2.2 вклинится другой поток типа N и также захватит сначала A, потом B. Это недопустимо. Освобождение и захват должны быть атомарной операцией.
Кажется что можно поменять пункты 2.1 и 2.2 местами, то есть сначала захватывать B, а потом освобождать A. Но на сцену выходят потоки типа M. Поток типа M может захватить B до захвата потоком I блокировки B и тогда A не освободится до освобождения потоком типа M блокировки B, что недопустимо. Допустимо, если поток I переключится на блокировку B, и подождет пока её освободит поток типа M. При этом во время ожидания блокировка A будет свободна.

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

1) Поток I типа N захватывает ресурс A.
2) Теперь потоку I требуется переключиться на блокировку ресурса B. Для этого
2.1) Поток I запускает дополнительный поток III. В этом потоке сначала захватывается B, потом выполняется код, который поток I хотел выполнить после переключения на блокировку ресурса B.
2.2) Поток I освобождает ресурс A
2.3) Поток I ждёт завершения потока III (.Join)

Хочется без создания дополнительных потоков. Может что-то с низкоуровневым примитивами синхронизации можно что-то замутить, может ReaderWriterLock как-то использовать
Отвечайте на это сообщение, только если у Вас хорошее настроение и в Вашем ответе планируются только конструктивные вопросы и замечания
http://rsdn.ru/Info/rules.xml
Отредактировано 22.09.2015 14:00 igor-booch . Предыдущая версия . Еще …
Отредактировано 22.09.2015 13:59 igor-booch . Предыдущая версия .
Отредактировано 22.09.2015 13:58 igor-booch . Предыдущая версия .
Отредактировано 22.09.2015 13:21 igor-booch . Предыдущая версия .
Отредактировано 22.09.2015 13:10 igor-booch . Предыдущая версия .
Отредактировано 22.09.2015 13:04 igor-booch . Предыдущая версия .
Re[2]: Двойная блокировка переключатель
От: igor-booch Россия  
Дата: 22.09.15 13:24
Оценка:
K>Может, я немножко не по теме влезу, однако хочу упомянуть одну статью: Advanced Techniques To Avoid And Detect Deadlocks In .NET Apps, by Joe Duffy. Была опубликована в журнале MSDN Magazine, потом мелкософт удалил онлайн-материалы и взамен предлагает скачивать журналы в формате chm. Взять можно здесь — April 2006. В ней автор приводит (в статье есть ссылка на скачку самораспаковывающегося архива с исходниками) класс LeveledLock, применение которого контролирует порядок взятия блокировок на разных ресурсах. Что позволит избежать дедлоков, о которых написал Sinclair.

Описал задачу по другому: http://rsdn.ru/forum/dotnet/6190267.1
Автор: igor-booch
Дата: 22.09.15
Отвечайте на это сообщение, только если у Вас хорошее настроение и в Вашем ответе планируются только конструктивные вопросы и замечания
http://rsdn.ru/Info/rules.xml
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 в том же порядке, как они получали доступ к А.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[5]: Двойная блокировка переключатель
От: Sinatr Германия  
Дата: 23.09.15 07:04
Оценка:
Здравствуйте, igor-booch, Вы писали:

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

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

А и B не связаны. Всем потокам (N и M) нужен B. Ресурс А необходимо только N потокам, они могут сначала захватить B, а уже затем отпускать А.
---
ПроГLамеры объединяйтесь..
Re[6]: Двойная блокировка переключатель
От: igor-booch Россия  
Дата: 23.09.15 07:35
Оценка:
S>В этот момент у потоков N1 и N2 равные шансы захватить B. Это означает, что с вероятностью 50% произойдёт сценарий вклинивания N2 внутрь транзакции, выполняемой N1, что по вашему второму требованию запрещено.
Вот и не должны быть равные шансы. Приоритет должен быть отдан N1, а N2 должен встать в очередь, так как N1 захватил A раньше, чем N2. Кто первым захватывает A, тот первым захватывает B. Вопрос топика как это реализовать?

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)
S>Вы же понимаете, что порядок выполнения 2.1 и 2.2 ничем не гарантирован? Т.е. поток I может освободить ресурс А задолго до того, как III захватит B. Поэтому функционально это решение эквивалентно неатомарному освобождению А, а затем захвату B.
Да это проблема, согласен
перед пунктом 2.2 думал покрутиться в цикле

while (thread.ThreadState == ThreadState.Unstarted) {}

Но это тоже не даёт гарантии.

Thread.MemoryBarrier не знаю, может ли помочь в этом случае

Вот и вопрос. Как гарантировать, что B будет захвачена в дополнительном потоке III (п. 2.1), раньше чем освободится A (п. 2.2)?

IB>>Хочется без создания дополнительных потоков. Может что-то с низкоуровневым примитивами синхронизации можно что-то замутить, может ReaderWriterLock как-то использовать

S>Я всё ещё не понимаю природы ваших ограничений. На первый взгляд, задача решается в том случае, если доступ к B будет рулиться не монитором, а очередью — чтобы гарантировать, что потоки получают доступ к B в том же порядке, как они получали доступ к А.
Спасибо, возможно это и есть решение: заюзать очередь и синхронизировать Monitor'ом добавление в неё Action'ов, которые должны выполняться либо в блокировке A, либо в блокировке B
Отвечайте на это сообщение, только если у Вас хорошее настроение и в Вашем ответе планируются только конструктивные вопросы и замечания
http://rsdn.ru/Info/rules.xml
Отредактировано 23.09.2015 12:56 igor-booch . Предыдущая версия . Еще …
Отредактировано 23.09.2015 7:49 igor-booch . Предыдущая версия .
Отредактировано 23.09.2015 7:46 igor-booch . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.