2009-02-16 2 views
1

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

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

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

ответ

14

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

if (Monitor.TryEnter(lockObj, 0)) { 
    // got the lock ! 
    try { 
     // code 
    } 
    finally { // release the lock 
     Monitor.Exit(lockObj); 
    } 
} 
+0

Это нормально, я буду использовать TryEnter, но можете ли вы объяснить, как это небезопасно? Благодарю. – marijne

+0

Ну, вы получаете доступ к знаку за пределами замка. Как это бывает, вы устанавливаете только значение false, но это означает, что вы можете отрицать существенный поток - я могу предвидеть проблемы. Так как относительно просто использовать TryEnter, я бы использовал это ... –

0

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

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

", но без других потоков, нагроможденных в ожидании получения блокировки." - то есть OP хочет, чтобы он был взаимоисключающим, но не блокирующим. –

+0

Это интересное требование. Мне никогда не нужен механизм блокировки. –

3

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

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

if(_flag) return; 

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

+0

Интересный ответ, спасибо! Я не рассматривал эффекты оптимизации. – marijne

Смежные вопросы