Создание потоков и объектов Thread

Вы можете создавать экземпляры объекта Thread двумя способами. Один вы уже видели: это создание нового потока и получение объекта Thread, позволяющего манипулировать новым потоком в этом процессе. Другой способ получить объект Thread для потока, исполняемого в данный момент, — вызов статического метода Thread. CurrentThread.

Управление временем существования потоков

Чтобы управлять активностью или временем жизни потока, надо решить массу задач. С этим позволяют справиться методы Thread. Например, довольно часто поток нужно приостановить. Это можно сделать, вызвав метод Thread. Sleep, который принимает единственный аргумент, представляющий собой время (в миллисекундах), на которое требуется приостановить поток. Заметьте: метод Thread.Sleep является статическим и не может быть вызван с экземпляром объекта Thread. На то есть веская причина. Не допускается вызывать Thread.Sleep для любого другого потока, кроме исполняемого в текущий момент. Статический метод Thread.Sleep вызывает статический же метод CurrentThread, который затем приостанавливает этот поток на указанное время.

Есть еще два способа вызова метода Thread.Sleep. Первый — вызов Thread. Sleep со значением 0. При этом вы заставите текущий поток освободить неиспользованный остаток своего кванта. При передаче значения Timeout. Infinite поток будет приостановлен на неопределенно долгий срок, пока это состояние потока не будет прервано другим потоком, вызвавшим Thread.Interrupt.

Второй способ приостановить исполнение потока — вызов метода Thread.Suspend. Между этими методиками несколько важных отличий. Во-первых, можно вызвать метод Thread. Suspend для потока, исполняемого в текущий момент, или для другого потока. Во-вторых, если таким образом приостановить выполнение потока, любой другой поток способен возобновить его выполнение с помощью метода Thread. Resume. Обратите внимание, что, когда один поток приостанавливает выполнение другого, первый поток не блокируется. Возврат управления после вызова происходит немедленно. Кроме того, единственный вызов Thread.Resume возобновит исполнение данного потока независимо от числа вызовов метода Thread.Suspend, выполненных ранее.

Уничтожение потоков

Уничтожить поток можно вызовом метода Thread.Abort. Исполняющая среда насильно завершает выполнение потока, генерируя исключение ThreadAbortException. Даже если метод попытается уловить ThreadAbort-Exception, исполняющая среда этого не допустит. Однако она исполнит код из блока finally потока, выполнение которого прервано, если этот блок присутствует.

Вы должны отдавать себе отчет в том, что при вызове метода Thread.Abort выполнение потока не может остановиться сразу. Исполняющая среда ожидает, пока поток не достигнет той точки, которая в документации названа "безопасной точкой" ("safe point"). Поэтому, если ваша программа зависит от некоторых действий, которые происходят после прерывания потока, и вам надо быть уверенными в том, что поток остановлен, вы можете использовать метод Thread. Join. Это синхронный вызов, т. е. он не вернет управление, пока поток не будет остановлен. Напоследок обратите внимание, что после прерывания поток нельзя перезапустить. В этом случае, несмотря на то, что у вас есть действительный объект Thread, от него нет никакой пользы в плане выполнения кода.

Планирование потоков

При переключении процессора по окончании выделенного потоку кванта времени, процесс выбора следующего потока, предназначенного для исполнения, далеко не произволен. У каждого потока есть приоритет, указывающий процессору, как должно планироваться выполнение этого потока по отношению к другим потокам системы. Для потоков, создаваемых в период выполнения, уровень приоритета по умолчанию равен Normal. Потоки, созданные не в период выполнения, сохраняют свой исходный приоритет. Для просмотра и установки этого значения служит свойство Thread.Priority. Установщик свойства Thread.Priority принимает аргумент типа Thread. ThreadPriority, который представляет собой enum, определяющий значения Highest, AboveNormal, Normal, BelowNormal и Lowest.

Помните, что когда вы указываете процессору приоритет, который вы хотите установить для данного потока, то его значение в конечном счете используется ОС как часть алгоритма планирования распределения процессорного времени. В .NET этот алгоритм основан на уровнях приоритета, которые вы только что использовали (с помощью свойства Thread.Priority), а также на классе приоритета (priority class) процесса и значении динамического повышения (dynamic boost) приоритета. С помощью всех этих значений создается численное значение (для процессоров Intel — 0—31), представляющее приоритет потока. Потоки с наибольшим значением являются самыми высокоприоритетными.

Наши рекомендации