Нэш Трей - C# 2010. Ускоренный курс для профессионалов (2010) (1160865), страница 95
Текст из файла (страница 95)
между тем выполнять какую-то другую работу. // Ожидать окончания работы. ргсс1.зотп О г ргос2.эотп(); эгаг1с ргтчаге ното Тпгеабрцпс( оЬ)есг сЬ> ) ( // Выполнить приведение вхоляшего объекта к Очесе. спеце СпеОцеце = (Очесе) оЬБ; опустошить очередь. 362 Глава 12 Шаблон 1ОЦ и асинхронные вызовы методов В разделе "Асинхронные вызовы методов" далее в главе, где обсуждается асинхронный ввод-вывод и пулы потоков. будет показано, что схема ВедьпРгосеззпага/ епбггосеззбаса является общепринятым шаблоном асинхронного программирования в .(чЕТ Егашекюг)г. Шаблон асинхронного программирования Вед1пнесьоб/ Епбиесйос1 в .НЕТ ргагпекюг)г подобен шаблону 1О(1, описанному Алленом Вермуленом (Айап Уеппец!еп) в его статье Ап Аэупсдгопоиз Вез(дп Ракегл (Асинхронный шаблон проектирования) в журнале ПгПоЬЬ'з,/оипкв( (июнь 1996 г).
В этом шаблоне для запуска асинхронной операции вызывается некоторая функция, и она возвращает вызывающему коду объект 1О11 ("1 ок~е уои" — "я владею тобой"). Позднее вызывающий код может использовать этот объект для получения результата асинхронной операции. Удобство этого шаблона в том, что он полностью отделяет вызывающий код, который желает получить готовую выполненную асинхронную работу, от механизма, применяемого для ее выполнения. Этот шаблон интенсивно используется в .
НЕТ Егашеаог)г, и его рекомендуется применять для асинхронных вызовов методов, поскольку он хорошо знаком вашим клиентам, и оии будут себя чувствовать уверенно. Состояния потока Состояния управляемого потока четко определены исполняющей средой. Хотя переходы между состояниями могут иногда показаться запуганными, все же они не намного сложнее, чем переходы между состояниями потока операционной системы. В мире управляемых приложений необходимо учитывать множество обстоятельств, поэтому вполне естественно, что допустимые состояния и переходы между ними достаточно сложны. На рис.
12.1 показана диаграмма состояний управляемых потоков. Состояния на этой диаграмме основаны на состояниях, которые определены С1Л для управляемых потоков и представлены в перечислении тьгеас1Бсасе. каждый управляемый поток начинает свое существование с состояния Бпзсагсеб. После вызова Благе на новом потоке он входит в состояние Випаапд. Потоки операционной системы, которые обслуживают управляемую исполняющую среду, немедленно стартуют в состоянии Вопо1пд, минуя состояние Впзсагсеб. Обратите внимание, что вернуться в состояние Бпзсагсеб невозможно.
Доминирующим состоянием на диаграмме является Випп1пд. Это состояние, в котором находится поток. когда он нормально выполняет код, в том числе обрабатывает любые исключения и выполняет блоки Тапа11у. Если главный метод потока, переданный в экземпляре делегата тьгеас1Бсагс во время создания этого потока, завершается нормально, то поток входит в состояние Р1п1з1~еб, как показано на рис. 12.1. Попав в это состояние, поток окончательно исчезает и уже никогда не возвращается к существованию. Если все фоновые потоки процесса достигают состояния Р1п1зьеб, процесс завершается нормально. Названные три состояния покрывают все основные переходы между состояниями потока, если предположить, что поток просто выполняет некоторый код и завершается.
Как только начать добавлять к пути выполнения конструкции синхронизации илн управлять состоянием потока, будь то из другого потока или текущего. все существенно усложняется. Например, предположим, что новый поток необходимо на некоторое время усыпить. Для этого придется вызвать ТЛгеас1.
Б1еер и указать таймаут — количество миллисекунд, на которые поток должен заснуть. Это подобно тому, как усыпляется поток операционной системы. Когда вызывается Б1еер, поток входит в состояние иаасБ1еерБоап, при котором его выполнение приостанавливается на заданный период таймауга. Как только этот период истекает, поток возвращается в состояние выполнения. Многопоточность в С№ 363 Рис. 12.1. Диаграмма состояний управляемых потоков 364 Глава 12 Операции синхронизации также могут перевести поток в состояние из1с я1еер,то1п. Как должно быть очевидным иэ названия состояния, вызов ТЬгезг!. тозп на другом потоке, предназначенный для того, чтобы заставить ждать его завершения. переводит вызывающий поток в состояние хазгя1еерлогп.
Вызов ноп1сог.иатс также переводит поток в состояние ха !.ЬЕ1ееряо1п. теперь вам известны три фактора, в первую очередь определившие названия состояний. Для синхронизации потоков можно использовать и другие методы, которые рассматриваются в разделе "Синхронизация работы между потоками" далее в главе. Как и ранее, если поток находится в состояния ожидания, он может быть принудительно возвращен обратно в состояние епппапд, когда другой поток вызовет тьгеас!. 1псеггпрг на ожидающем потоке. программисты уу!п32 узнают в этом поведении нечто подобное изменяемым состояниям ожидания в операционной системе. имейте в виду, что когда поток вызывает тьгезц.
1пгеггпрг на другом потоке, то прерываемый поток получает исключение тпгезс!1псеггпрсес!ехсерг1оп. Поэтому, несмотря на то, что прерванный поток возвращается в состояние Еипп1пд, он не может оставаться в нем долго, если только у него не окажется соответствующих средств обработки исключения. В противном случае поток скоро войдет в состояние Езп1зпес!. как только исключение завершит свой путь к вершине стека, будучи не обработанным. Другой путь, которым поток может покинуть состояние на1ся1еер Яо1п — это когда другой поток вызывает ТЬгезс!. АЬогг на текущем потоке. Формально поток может вызвать АЬогс на самом себе. Однако это довольно редкий вариант потока выполнения, и потому на рис. 12.1 он не показан.
После вызова Тлгезс!. АЬогг поток входит в состояние Аьогсеес!иезсег!. Это состояние в действительности является формой состояния выполнения, поскольку в потоке сгенерировано исключение тьгезольогтехсергзоп, и он должен его обработать. Однако, как будет объясняться позже, управляемый поток трактует это исключение специальным образом — так, что следующим состоянием будет АЬоггес1, если только поток, вызвавший ТЬгезс!. АЬогг, не вЫЗОвет ТЬгеаб. РезеСАЬогг до того, как это случится. Кстати, ничего не может остановить поток, который прерывается по вызову еезесАЬогс.
Однако от подобных вещей следует воздерживаться, поскольку они могут привести к проблемному поведению. Например, если поток переднего плана не сможет быть прекращен. потому что он находится в состоянии сброса. то процесс не завершится никогда. На заметку! Начиная с .НЕТ 2.0, хост имеет возможность принудительно уничтожать потоки во время останова домена приложения, используя т.н. грубое прерывание потока. В такой ситуации существование потока не может быть продлено с помощью тьгеас!.
еезесльогг. И, наконец, выполшпощийся поток входит в состояние яцзрепс!Ееопезсес! после вызова ТЬгеас. Яизрепг! на нем самом или же когда другой поток вызовет Яизрепс! на нем. Очень скоро после этого поток автоматически входит в состояние Япзрепбес!. Далее в разделе "Останавливающиеся и пробуждающиеся потоки" рассказывается, зачем нужны эти промежуточные состояния для приостановленного потока. А пока важно запомнить, что состояние яцзрепс!Яеопезсеб — это форма состояния выполнения в том смысле, что в этом состоянии продолжается выполнение управляемого кода.
На этом краткий обзор переходов между состояниями управляемых потоков завершен. При рассмотрении далее в главе вопросов, связанных с состоянием потока, не забывайте заглядывать на рис. 12.1. Завершение потоков При вызове тьгезб. АЬогс рассматриваемый поток, в конце концов, получает Тпгеас!АЬогсехсерс1оп. Поэтому, естественно, для аккуратного обслуживания этой Многопоточность в С() 365 ситуации необходимо обрабатывать исключение ТЬгеас(АЬоггЕхсерс1оп, если поток должен делать что-то особенное в случае его прерывания. Существует даже перегрузка АЬогс,которая принимает произвольную объектную ссылку,инкапсулируемую затем в тьгеасйьогсехсерс1оп. Это позволяет коду, прерывающему поток, передать некоторую контекстную информацию обработчику Тпгеас(АЬогГЕхсерг1оп, например, причину вызова АЬогг. СЕВ не доставляет ТЬгеасйЬоггЕхсерс гоп, ЕСЛИ ТОЛЬКО ПОТОК НЕ ВЫПОЛняется внУтри управляемого контекста.












