2016-01-15 3 views
0

Сегодня я столкнулся с этим: https://blogs.msdn.microsoft.com/ericlippert/2009/03/06/locks-and-exceptions-do-not-mix/.net 2.0 блокировка и исключения перед попыткой-наконец. Есть ли другие исключения, кроме прерывания потока?

Я использую .net 2.0, так что, в принципе, этот код

lock(syncRootVar) { 
    DoStuff(); 
} 

будет разворачиваться в этом

Monitor.Enter(syncRootVar); 
try { 
    DoStuff(); 
} finally { 
    Monitor.Exit(syncRootVar); 
} 

Как писал Lippert в блоге может быть операция nop между вызовом Enter и блоком try-finally, являющимся потенциальной позицией для исключения прерывания потока, которое должно быть поднято, и, следовательно, испортить блокировку.

У меня есть два вопроса по этому поводу:

  • Есть ли общий способ обработки этой нежелательной ситуации, и до сих пор очистить объект блокировки для того, чтобы не влиять на другие темы?
  • Существуют ли другие ситуации, которые могут привести к приобретению блокировки, но исключения, возникающие перед блоком try-finally?

ответ

0

Как указано в статье, проблема, с которой вы, похоже, беспокоитесь, больше не является проблемой. Компилятор C# был изменен (и предположительно с Roslyn сохранит изменение), чтобы блокировка была сделана внутри try/finally. Невозможно выполнить блокировку, но не выполнить предложение finally.

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


• Существует ли общий способ обработки этой нежелательной ситуации, и до сих пор очистить объект блокировки для того, чтобы не влиять на другие темы?

Для конкретной ситуации вы просили о, два самых больших вещей, которые вы можете сделать это:

  1. Не прерывать нити. Это всегда хороший совет и всегда следует соблюдать. Если вы не прервите нить, у вас не будет этой проблемы.
  2. Используйте последнюю версию компилятора. Более новые версии компилятора не генерируют код, который был бы восприимчивым к этой проблеме.

• Существуют ли другие ситуации, которые могут привести к замку приобретаемые, но исключения повышения до примерки, наконец, блок?

Нет, не с последней версией компилятора. Нет даже первоначальной ситуации.


Теперь как насчет этой досадной «частично мутированной» проблемы? Ну, вам придется решать каждый случай индивидуально. Но если можно было бы исключить исключение и оставить блокировку с частично мутированным состоянием, то вам придется добавить свой собственный код очистки. Например:

lock(syncRootVar) { 
    try { 
     DoStuff(); 
    } catch { 
     UndoStuff(); 
     throw; 
    }  
} 
Смежные вопросы