Глава.22 .Хостинг.CLR.и.домены.приложений
вызывает метод
Abort
типа
Thread
, требуя от CLR остановить поток из пула
и вынуждая выдать исключение
ThreadAbortException
.
6. На этом этапе поток пула начинает завершение, вызывая блоки
finally
, чтобы
выполнить код очистки. В итоге поток возвращается в домен. Так как программа-
заглушка вызвала сторонний код из блока
try
, в ней имеется и блок
catch
,
который перехватывает исключение
ThreadAbortException
.
7. В ответ на перехват исключения
ThreadAbortException
хост вызывает метод
ResetAbort
типа
Thread
. Зачем это нужно, я объясню чуть позже.
8. Хост отправляет информацию о сбое клиенту и возвращает поток в пул, чтобы
его можно было снова задействовать для обслуживания клиентских запросов.
рис. 22.3.
.Возвращение.хостом.контроля.над.потоком
Проясню некоторые непонятные места этой архитектуры. Во-первых, метод
Abort
типа
Thread
выполняется асинхронно. Он отмечает целевой поток флагом
AbortRequested
и немедленно возвращает управление. Обнаружив завершение по-
тока, исполняющая среда пытается перенести этот поток в
безопасное место
(safe
place). Исполняющая среда считает, что поток находится в безопасном месте, если
его можно (по ее мнению) остановить без риска серьезных последствий. Поток на-
ходится в безопасном месте, если выполняет управляемую операцию блокировки,
например бездействует или «спит». Перемещение в безопасное место осуществля-
ется путем захвата (см. главу 21). Поток не считается находящимся в безопасном
месте, если он выполняет конструктор класса типа, код блока
catch
или
finally
,
код в критической области или неуправляемый код.
Как только поток оказывается в безопасном месте, исполняющая среда об-
наруживает у него флаг
AbortRequested
и заставляет его выдать исключение
ThreadAbortException
. Если исключение не перехватывается, оно остается необра-
ботанным, выполняются все блоки
finally
и поток корректно завершается. В отли-
чие от всех прочих, оставшись необработанным, исключение
ThreadAbortException
635
Нетривиальное.управление.хостингом
не приводит к остановке приложения. Исполняющая среда поглощает его, и поток
завершается, но приложение и все оставшиеся его потоки продолжают работу.
В рассматриваемом примере хост перехватывает исключение
ThreadAbort-
Exception
, получая возможность снова получить контроль над потоком и возвратить
его в пул. Однако остается вопрос: что может помешать стороннему коду перехватить
исключение
ThreadAbortException
, чтобы сохранить за собой контроль над потоком?
У CLR к данному исключению особое отношение. Даже если код перехватывает ис-
ключение
ThreadAbortException
, CLR в конце блока
catch
автоматически повторно
его генерирует.
В связи с этой особенностью CLR возникает вопрос: если CLR повторно генери-
рует исключение
ThreadAbortException
в конце блока
catch
, как же хосту удается
перехватить это исключение и восстановить контроль над потоком? В блоке
catch
хоста есть вызов метода
ResetAbort
типа
Thread
. Именно он запрещает CLR повторно
генерировать исключение
ThreadAbortException
в конце каждого блока
catch
.
Тогда снова возникает вопрос: а что может запретить стороннему коду перехватить
исключение
ThreadAbortException
и самому вызвать метод
ResetAbort
типа
Thread
?
К счастью, для вызова этого метода у вызывающей программы должно быть разреше-
ние
SecurityPermission
с флагом
ControlThread
, имеющим значение
true
. Создавая
домен для кода сторонних разработчиков, хост не предоставляет такое разрешение,
а, значит, такой код не сможет сохранить за собой контроль над его потоком.
Должен заметить, что брешь в системе безопасности в данном случае все-таки воз-
можна: когда поток раскручивает исключение
ThreadAbortException
, сторонний код
может выполнить блоки
catch
и
finally
, содержащие код с бесконечным циклом, не
позволяющим хосту вернуть контроль над потоком. Эта проблема решается при по-
мощи обсуждавшейся ранее политики расширения. Если останавливаемый поток не
завершается за разумное время, CLR может перейти от корректной к принудительной
остановке, принудительной выгрузке домена, отключению CLR или уничтожению
процесса. Следует также заметить, что сторонний код может перехватить исключение
ThreadAbortException
и вбросить в блоке
catch
какое-то другое исключение. Если
оно перехватывается, в конце блока
catch
CLR автоматически повторно выдаст ис-
ключение
ThreadAbortException
.
Большинство сторонних программ не представляет угрозы — просто с точки
зрения хоста они тратят на решение своей задачи слишком много времени. Обычно
блоки
catch
и
finally
содержат очень немного кода, выполняемого быстро без
каких-либо бесконечных циклов или «долгоиграющих» операций. Поэтому вряд ли
вам потребуется политика расширения для возвращения управления потоком хосту.
Кстати, у класса
Thread
есть два метода
Abort
: один без параметров, а второй
с параметром
Object
, в котором можно передать любой объект. Перехватив исклю-
чение
ThreadAbortException
, код может запросить свое предназначенное только
для чтения свойство
ExceptionState
, которое вернет объект, переданный в качестве
параметра. Это позволяет потоку, вызвавшему метод
Abort
, передать дополнитель-
ную информацию коду, перехватившему исключение
ThreadAbortException
. Хост
может использовать это для информирования собственного перехватывающего кода
о причине остановки потока.
Do'stlaringiz bilan baham: |