Взаимное исключение: это безопасно? - PullRequest
1 голос
/ 16 февраля 2009

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

lock (_lock) {
    if (_flag) return;
    else _flag = true;
}
try {
    //critical code...
}
finally {
    _flag = false;
}

Я хочу обеспечить критическую секцию, но без накопления других потоков в ожидании блокировки. Очевидно, я удостоверяюсь, что флаг установлен нигде больше. Есть ли лучший способ?

Ответы [ 4 ]

14 голосов
/ 16 февраля 2009

Нет, это не безопасно. Если вы хотите обеспечить взаимоисключающие без блокировки, вы можете использовать Monitor.TryEnter:

if (Monitor.TryEnter(lockObj, 0)) {
    // got the lock !
    try {
        // code
    }
    finally { // release the lock
        Monitor.Exit(lockObj);
    }
}
5 голосов
/ 16 февраля 2009

Вы смотрели на Monitor.TryEnter?

3 голосов
/ 17 февраля 2009

Правильность вашего шаблона взаимного исключения зависит от присваивания _flag = false, являющегося атомным. Представьте, что произойдет, если назначение может быть прервано другим потоком. Если промежуточные результаты назначения могут быть интерпретированы тестом как ложные, одно назначение может привести к тому, что несколько потоков попадут в критическую секцию.

Правильность шаблона взаимного исключения также зависит от отсутствия оптимизаций в компиляторе, которые могут изменить порядок операторов. Представьте себе «умный» компилятор, который будет перемещать присваивание _flag = false вверх, потому что _flag не упоминается в промежуточном коде (а промежуточный код не генерирует исключения). Затем компилятор может оптимизировать часть в секции блокировки так, чтобы она прочитала

if(_flag) return;

Оба примера того, почему шаблон может потерпеть неудачу, весьма умозрительны, и я думаю, что вы уверены, что он работает. Однако, при наличии другой опции, которая работает как требуется, вам лучше использовать ее (см. Другие посты). Если в том же коде есть другие разработчики, им не нужно учитывать, работает ли шаблон.

0 голосов
/ 16 февраля 2009

Разве простой lock(Object) оператор не сработает? За кулисами создается Monitor и критическая секция внутри блока try... finally.

private static readonly Object lockMe = new Object();
lock(lockMe)
{
    // critical code
}
...