Состояния потока в C#

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

Состояния на этой диаграмме основаны на состояниях, которые определены CLR для управляемых потоков и представлены в перечислении ThreadState. Каждый управляемый поток начинает свое существование с состояния Unstarted. После вызова Start на новом потоке он входит в состояние Running.

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

Доминирующим состоянием на диаграмме является Running. Это состояние, в котором находится поток, когда он нормально выполняет код, в том числе обрабатывает любые исключения и выполняет блоки finally. Если главный метод потока, переданный в экземпляре делегата ThreadStart во время создания этого потока, завершается нормально, то поток входит в состояние Finished, как показано на рисунке.

Попав в это состояние, поток окончательно исчезает и уже никогда не возвращается к существованию. Если все фоновые потоки процесса достигают состояния Finished, процесс завершается нормально.

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

Например, предположим, что новый поток необходимо на некоторое время усыпить. Для этого придется вызвать Thread.Sleep и указать таймаут — количество миллисекунд, на которые поток должен заснуть. Это подобно тому, как усыпляется поток операционной системы.

Когда вызывается Sleep, поток входит в состояние Wait Sleep Join, при котором его выполнение приостанавливается на заданный период таймаута. Как только этот период истекает, поток возвращается в состояние выполнения.

Операции синхронизации также могут перевести поток в состояние WaitSleepJoin. Как должно быть очевидным из названия состояния, вызов Thread.Join на другом потоке, предназначенный для того, чтобы заставить ждать его завершения, переводит вызывающий поток в состояние WaitSleepJoin.

Вызов Monitor.Wait также переводит поток в состояние WaitSleepJoin. Теперь вам известны три фактора, в первую очередь определившие названия состояний.

Как и ранее, если поток находится в состояния ожидания, он может быть принудительно возвращен обратно в состояние Running, когда другой поток вызовет Thread.Interrupt на ожидающем потоке.

Программисты Win32 узнают в этом поведении нечто подобное изменяемым состояниям ожидания в операционной системе. Имейте в виду, что когда поток вызывает Thread.Interrupt на другом потоке, то прерываемый поток получает исключение ThreadlnterruptedException.

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

Другой путь, которым поток может покинуть состояние WaitSleepJoin — это когда другой поток вызывает Thread.Abort на текущем потоке. Формально поток может вызвать Abort на самом себе. Однако это довольно редкий вариант потока выполнения, и потому на рисунке он не показан.

После вызова Thread.Abort поток входит в состояние AbortRequested. Это состояние в действительности является формой состояния выполнения, поскольку в потоке сгенерировано исключение ThreadAbortException, и он должен его обработать. Однако, как будет объясняться позже, управляемый поток трактует это исключение специальным образом — так, что следующим состоянием будет Aborted, если только поток, вызвавший Thread.Abort, не вызовет Thread.ResetAbort до того, как это случится. Кстати, ничего не может остановить поток, который прерывается по вызову ResetAbort.

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

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

И, наконец, выполняющийся поток входит в состояние SuspendRequested после вызова Thread.Suspend на нем самом или же когда другой поток вызовет Suspend на нем. Очень скоро после этого поток автоматически входит в состояние Suspended.

А пока важно запомнить, что состояние SuspendRequested — это форма состояния выполнения в том смысле, что в этом состоянии продолжается выполнение управляемого кода.

На этом краткий обзор переходов между состояниями управляемых потоков завершен.

Вы можете следить за любыми ответами на эту запись через RSS 2.0 ленту. Вы можете оставить ответ, или trackback с вашего собственного сайта.

Оставьте отзыв

XHTML: Вы можете использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

 
Rambler's Top100