области с ограничением выполнения

Область ограниченного выполнения (CER) является одной из составляющих механизма создания надежного управляемого кода. В этой области общеязыковая среда выполнения (CLR) не может выдавать специализированные исключения, препятствующие полному выполнению заключенного в эту область кода. В этой области не может выполняться пользовательский код, в результате которого могут возникать специализированные исключения. Метод PrepareConstrainedRegions указывается непосредственно перед блоком try и помечает блоки catch, finally и fault как области ограниченного выполнения. После определения области ограниченного выполнения код может вызывать только другой код со строгими контрактами надежности и не должен выделять память или выполнять виртуальные вызовы для неподготовленных или ненадежных методов, если в таком коде не предусмотрены механизмы обработки сбоев. Среда выполнения задерживает аварийные завершения потоков для кода, который выполняется в области ограниченного выполнения.

Важно!

CER поддерживается только в .NET Framework. Эта статья не относится к .NET Core, .NET 5 и более поздним версии.

Области ограниченного выполнения применяются в среде CLR в различных формах, в том числе в указанном выше блоке try. Часто это могут быть критически важные методы завершения, которые выполняются в производных от CriticalFinalizerObject классах, или код, выполняемый в методе ExecuteCodeWithGuaranteedCleanup.

Заблаговременная подготовка области ограниченного выполнения

Среда CLR подготавливает область ограниченного выполнения заранее, чтобы избежать ошибок, связанных с нехваткой памяти. Таким образом удается исключить нехватку памяти во время JIT-компиляции или загрузки типов.

Разработчик должен явно определить нужный фрагмент кода как область ограниченного выполнения:

  • Область ограниченного выполнения верхнего уровня и методы в полном графе вызовов, к которым применяется атрибут ReliabilityContractAttribute, подготавливаются заранее. Атрибут ReliabilityContractAttribute может гарантировать только состояния Success или MayFail.

  • Заблаговременная подготовка невозможна для вызовов, которые нельзя определить статически, таких как вызовы виртуальной диспетчеризации. В таких случаях следует использовать метод PrepareMethod. При использовании метода ExecuteCodeWithGuaranteedCleanup необходимо применять атрибут PrePrepareMethodAttribute для очистки кода.

Ограничения

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

  • Явное выделение памяти.

  • Упаковка-преобразование.

  • Получение блокировки.

  • Виртуальный вызов неподготовленных методов.

  • Вызов методов со слабым или отсутствующим контрактом надежности.

Для платформы .NET Framework версии 2.0 эти ограничения устанавливаются как правила. Для диагностики применяются средства анализа кода.

Контракты надежности

Настраиваемый атрибут ReliabilityContractAttribute определяет гарантированную надежность и состояние повреждения для указанного метода.

Гарантии надежности

Гарантии надежности представляются значениями перечисления Cer и определяют степень надежности указанного метода:

  • MayFail. Метод может завершиться сбоем в состоянии исключения. В этом случае метод возвращает вызывающему методу сведения об успешном или неудачном выполнении. Такой метод должен размещаться в области ограниченного выполнения, чтобы гарантированно передавать возвращаемое значение.

  • None. Метод, тип или сборка не поддерживает механизм области ограниченного выполнения и, скорее всего, не может безопасно вызываться в ней без надлежащих мер по исключению поврежденного состояния. Этот метод не использует преимущества гарантий для области ограниченного выполнения. В этом случае подразумевается следующее:

    1. Метод может завершиться сбоем в состоянии исключения.

    2. Метод не может гарантированно возвращать сообщение о сбое.

    3. В большинстве случаев этот метод не предназначен для использования в областях ограниченного выполнения.

    4. Если метод, тип или сборка не имеют явного определения успешного выполнения, они будут неявно определены как None.

  • Success. В состоянии исключения гарантируется успешное выполнение метода. Чтобы достичь этого уровня надежности, необходимо всегда строить область ограниченного выполнения вокруг метода, который вызывается, даже если он вызывается не из такой области. Состояние успеха достигается в том случае, если метод выполнил предусмотренные операции либо завершился успешно с субъективной точки зрения. Например, если метод Count отмечен как ReliabilityContractAttribute(Cer.Success), подразумевается, что он выполняется в области ограниченного выполнения, всегда возвращает число элементов в ArrayList и никогда не оставляет внутренние поля в неопределенном состоянии. Тем не менее метод CompareExchange также помечен как успешный в том смысле, что его значение не может быть заменено новым из-за возникновения состояния гонки. В этом случае важно, что метод функционирует в точном соответствии с задокументированным поведением. Соответственно, для него не нужно писать код области ограниченного выполнения для обработки возможных непредвиденных результатов, которые может давать правильно написанный, но не являющийся надежным код.

Уровни повреждения

Уровни повреждения представлены значениями перечисления Consistency и указывают возможную степень повреждения состояния в указанной среде:

  • MayCorruptAppDomain. В состоянии исключения общеязыковая среда выполнения (CLR) не гарантирует обеспечение согласованности состояния в текущем домене приложения.

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

  • MayCorruptProcess. В состоянии исключения среда CLR не гарантирует согласованность состояния, то есть такое условие может привести к повреждению процесса.

  • WillNotCorruptState. В состоянии исключения гарантируется, что метод не приведет к повреждению состояния.

Надежность блоков try/catch/finally

Надежность блоков try/catch/finally определяет механизм обработки исключений с тем же уровнем гарантий предсказуемости, что и неуправляемая версия. Блок catch/finally представляет собой область ограниченного выполнения. Методы в этом блоке подготавливаются заранее и не должны прерываться.

На платформе .NET Framework версии 2.0 код информирует среду выполнения о надежности блока try, вызывая PrepareConstrainedRegions непосредственно перед этим блоком. PrepareConstrainedRegions является членом вспомогательного класса компилятора RuntimeHelpers. Ожидается реализация прямого вызова метода PrepareConstrainedRegions посредством компиляторов.

Непрерываемые области

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

На платформе .NET Framework версии 2.0 (ожидается доступность посредством компиляторов) пользовательский код создает непрерываемые области с надежными блоками try/catch/finally, содержащие пустой блок try/catch block, которому предшествует вызов метода PrepareConstrainedRegions.

Объект критически важного метода завершения

CriticalFinalizerObject гарантирует, что в методе завершения будет выполнена сборка мусора. После выделения памяти метод завершения и его граф вызовов подготавливаются заблаговременно. Метод завершения выполняется в области ограниченного выполнения и должен соответствовать всем ограничениям, которые применяются к таким областям и методам.

Для всех типов, наследуемых от SafeHandle и CriticalHandle, гарантируется выполнение метода завершения в области ограниченного выполнения. Для выполнения любого кода, для которого требуется высвобождение дескриптора, реализуйте ReleaseHandle в производных от SafeHandle классах.

Код, который нельзя выполнять в областях ограниченного выполнения

В областях ограниченного выполнения не допускаются следующие операции:

  • Явное выделение памяти.

  • Получение блокировки.

  • Упаковка-преобразование.

  • Доступ к многомерным массивам.

  • Вызовы методов посредством отражения.

  • Enter или Lock.

  • Проверки безопасности. Нельзя выполнять запросы, только требования ссылок.

  • Isinst и Castclass для COM-объектов и прокси-элементов.

  • Получение или установка полей для прозрачных прокси.

  • Сериализация.

  • Указатели на функции и делегаты.

См. также