Мне нужно учитывать тот факт, что код в этом блоке блокировки может выдать исключение
И есть ваша проблема.Это ужасная ситуация.
Почему вы блокируете в первую очередь?Обычно причина, по которой вы что-то блокируете, заключается в том, что вы хотите реализовать следующую логику:
- запереть дверь
- устроить беспорядок
- вычистить ее
- отпереть дверь
Если вы сделаете это, то никто, кто почтит запертую дверь, никогда не увидит беспорядок.
Например, вы можете поменять местами значения переменных «влево» и «вправо», чтобы вы:
- взяли блокировку
- читать левую переменную в 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
}
}
Если у вас есть строгие требования к надежности, тогда работа с заблокированными критическими секциями, которые могут генерировать исключения, является чрезвычайно сложной задачей программирования.оставлен экспертам;вы можете рассмотреть возможность использования ограниченной области исполнения , если вы часто окажетесь в этой ситуации.