Подтвердить что ты не робот

Блокировка ресурса через блокировку внутри try. Это неправильно?

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

try  
{  
   lock(syncblk)  
   {  
        // do some processing  
    }  

}  
catch(Exception e)  
{  
    // do something with exception  
}  
4b9b3361

Ответ 1

Мне нужно иметь дело с тем, что код внутри этого блока блокировки может генерировать исключение

И вот твоя проблема. Это ужасная ситуация.

Почему вы заперты в первую очередь? Обычно причиной блокировки является то, что вы хотите реализовать следующую логику:

  • заблокировать дверь
  • сделать беспорядок
  • очистить его
  • откройте дверь

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

Например, вы можете поменять значения переменных "left" и "right" в потоковом режиме, чтобы вы:

  • возьмите блокировку
  • прочитайте левую переменную в tempLeft
  • прочитайте правую переменную в tempRight
  • написать tempLeft вправо
  • мы просто сделали беспорядок; исходное значение "права" пропало без вести.
  • написать tempRight влево
  • мы очистили беспорядок, все хорошо с миром снова
  • отпустите блокировку

Теперь предположим, что исключение вызывается после создания беспорядка. Что происходит? Мы прыгаем прямо к разблокировке, оставляя беспорядок для другого потока, чтобы видеть.

Вот почему вы должны никогда не бросать исключение внутри блокировки; он полностью побеждает цель замка! Вся точка блокировки состоит в том, чтобы гарантировать, что состояние всегда соблюдается в соответствии со всеми потоками, кроме одного, ответственного за очистку беспорядка.

Если у вас есть исключение, которое может быть выброшено изнутри блокировки, лучше всего выйти из этой ужасной ситуации. Если вы не можете этого сделать, убедитесь, что вы можете (1) полностью уничтожить процесс, как только исключение ускользает от блокировки, так что беспорядок, который вы сделали, не может привести к потере данных или другому вреду - сделайте a FailFast и вывести процесс с орбиты, это единственный способ убедиться - или (2) записать код отката, который отменяет любую операцию, которую вы пытались выполнить до блокировка завершена; то есть очистить беспорядок до исходного состояния.

Если последняя ваша стратегия, не ставьте блок try за пределы блокировки; это бесполезно там, потому что мгновенный элемент управления оставляет блокировку за исключением того, что другой поток может терпеть крах и умирать из-за беспорядка, который вы оставили на нем.. Поместите попытку, которая имеет дело с исключением внутри блокировки:

lock(whatever)
{
    try
    {
        MakeAMess();
    }
    finally
    {
        CleanItUp();
        // Either by completing the operation or rolling it back 
        // to the pre-mess state
    }
}

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

Ответ 2

Я думаю, вы можете сделать это по-своему, но вот описание MSDN для блокировки для вашей информации. Для получения дополнительной информации см. http://msdn.microsoft.com/en-us/library/ms173179.aspx.

Использование блокировки (С#) или SyncLock (Visual Basic), как правило, предпочтительнее использовать класс Monitor напрямую, так как блокировка или SyncLock более краток, и потому блокировки или SyncLock гарантирует, что основной монитор выпущен, даже если защищенный код исключение. Это достигается с помощью ключевое слово finally, которое выполняется связанный с ним кодовый блок независимо отбрасывается ли исключение.

Поэтому я не уверен, какое исключение вы имеете в виду, но если вы обеспокоены тем, что вы не сможете освободить блокировку из-за исключения, вам не нужно беспокоиться об этом.

Ответ 3

вы всегда можете использовать более длинный синтаксис следующим образом:

System.Threading.Monitor.Enter(x);
try {
   ...
}
catch(Exception e)
{
}
finally {
   System.Threading.Monitor.Exit(x);
}