блокировка ресурса через блокировку в пределах попытки. Это неправильно? - PullRequest
20 голосов
/ 14 мая 2011

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

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

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

Ответы [ 3 ]

41 голосов
/ 14 мая 2011

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

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

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

  • запереть дверь
  • устроить беспорядок
  • вычистить ее
  • отпереть дверь

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

Например, вы можете поменять местами значения переменных «влево» и «вправо», чтобы вы:

  • взяли блокировку
  • читать левую переменную в tempLeft
  • читать правую переменную в tempRight
  • записывать tempLeft в правую
  • мы только что запутались;первоначальное значение 'right' пропало
  • записать tempRight влево
  • мы убрали беспорядок, все в порядке с миром снова
  • снять блокировку

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

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

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

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

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

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

0 голосов
/ 14 мая 2011

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

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

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

0 голосов
/ 14 мая 2011

вы всегда можете использовать более длинный синтаксис, как этот:

System.Threading.Monitor.Enter(x);
try {
   ...
}
catch(Exception e)
{
}
finally {
   System.Threading.Monitor.Exit(x);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...