Как я могу написать условную блокировку в C #? - PullRequest
7 голосов
/ 28 октября 2008

Дело в том, что я использовал оператор lock для защиты критической части моего кода, но теперь я понимаю, что могу разрешить одновременное выполнение этого критического кода, если выполняются некоторые условия.
Есть ли способ кондиционировать замок?

Ответы [ 7 ]

9 голосов
/ 28 октября 2008

Я думаю, что этот вопрос кричит "состояние гонки!" Что если условие меняется с true на false вскоре после проверки, но до того, как поток входит в критическую часть кода? Или когда поток находится в процессе его выполнения?

8 голосов
/ 28 октября 2008

Я не эксперт по потокам, но звучит так, как будто вы ищете что-то вроде этого (двойная проверка блокировки). Идея состоит в том, чтобы проверить состояние до и после получения блокировки.

private static object lockHolder = new object();

if (ActionIsValid()) {
  lock(lockHolder) {
    if (ActionIsValid()) {
       DoSomething();    
    }
  }
}
7 голосов
/ 28 октября 2008
bool locked = false;
if (condition) {
    Monitor.Enter(lockObject);
    locked = true;
}
try {
    // possibly critical section
}
finally {
    if (locked) Monitor.Exit(lockObject);
}

РЕДАКТИРОВАТЬ: да, есть состояние гонки, если вы не можете гарантировать, что условие является постоянным, когда потоки вступают.

6 голосов
/ 28 октября 2008
Action doThatThing = someMethod;

if (condition)
{
  lock(thatThing)
  {
     doThatThing();
  }
}
else
{
  doThatThing();
}
4 голосов
/ 28 октября 2008

На самом деле, чтобы избежать состояния гонки, я хотел бы использовать здесь ReaderWriterLockSlim - обрабатывать одновременный доступ как блокировку чтения, а исключительный доступ как блокировку записи. Таким образом, если условия изменятся, вы не получите неуместный код, все еще выполняющийся вслепую в регионе (при ложном предположении, что это безопасно); немного многословно, но (отформатировано для пробела):

        if (someCondition) {
            lockObj.EnterReadLock();
            try { Foo(); }
            finally { lockObj.ExitReadLock(); }
        } else {
            lockObj.EnterWriteLock();
            try { Foo(); }
            finally { lockObj.ExitWriteLock(); }
        }
2 голосов
/ 10 ноября 2008

Использовать Дважды проверить схему блокировки , как предложено выше. это трюк ИМО :) 1003 *

убедитесь, что у вас есть объект блокировки как статический , как указано в примере not.that.dave.foley.myopenid.com.

1 голос
/ 28 октября 2008

Полагаю, у вас есть код, который выглядит примерно так:

private Monkey GetScaryMonkey(int numberOfHeads){
    Monkey ape = null;        
    lock(this) {
        ape = new Monkey();
        ape.AddHeads(numberOfHeads);            
    }
    return ape;
}

Чтобы сделать это условным, ты не мог просто сделать это:

private Monkey GetScaryMonkey(int numberOfHeads){
    if ( numberOfHeads > 1 ) {
         lock(this) {
            return CreateNewMonkey( numberOfHeads );          
        }
    }
    return CreateNewMonkey( numberOfHeads );
}

Должно работать, нет?

...