Пул потоков CLR
Пул потоков CLR
Заключительной темой нашего обсуждения в этой плаве, посвященной потокам, будет пул потоков CLR. При асинхронном вызове типов с помощью делегатов (посредством метода BeginInvoke()) нельзя сказать, что среда CLR буквально создает совершенно новый поток. В целях эффективности метод BeginInvoke() делегата использует пул (динамическую область) рабочих потоков, поддерживаемых средой выполнения. Чтобы позволить вам взаимодействовать с этим пулом рабочих потоков, пространство имен System.Threading предлагает тип класса ThreadPool.
Чтобы поставить вызов метода в очередь для обработки рабочим потоком из пула, используйте метод ThreadPool.QueueUserWorkItem(). Этот метод является перегруженным, чтобы вдобавок к экземпляру делегата WaitCallback имелась возможность указать необязательный System.Objеct для пользовательских данных состояния.
public sealed class ThreadPool {
…
public static bool QueueUserWorkItem(WaitCallback callBack);
public static bool QueueUserWorkItem(WaitCallback callBack, object state);
}
Делегат WaitCallback может указывать на любой метод, имеющий один параметр System.Object (для представления необязательных данных состояния) и не возвращающий ничего. Если при вызове QueueUserWorkItem() вы не предложите System.Object, среда CLR автоматически передаст значение null. Для иллюстрации методов очереди при использовании пула потоков CLR давайте рассмотрим следующую программу, в которой снова используется тип Printer. Но на этот раз мы не будем создавать массив типов Thread вручную, а свяжем метод PrintNumbers() с членами пула.
class Program {
static void Main(string[] args) {
Console.WriteLine("Старт главного потока. ThreadID = {0}", Thread.CurrentThread.GetHashCode());
Printer p = new Printer();
WaitCallback workItem = new WaitCallback(PrintTheNumbers);
// Очередь из 10 вызовов метода.
for (int i = 0; i ‹ 10; i++) {
ThreadPool.QueueUserWorkItem(workItem, p);
}
Console.WriteLine("Все задачи в очереди");
Console.ReadLine();
}
static void PrintTheNumbers(object state) {
Printer task = (Printer)state;
task.PrintNumbers();
}
}
Здесь вы можете спросить, разве выгодно использовать поддерживаемый средой CLR пул потоков вместо явного создания объектов Thread? Тогда рассмотрите следующие главные преимущества использования пула.
• Пул потоков управляет потоками эффективнее, поскольку минимизируется число потоков, которые приходится создавать, запускать и останавливать.
• При использовании пула потоков вы можете сосредоточиться на своей конкретной задаче, не отвлекаясь на вопросы инфраструктуры потоков приложения.
Однако управление потоками "вручную" может оказаться предпочтительнее, например, в следующих случаях.
• Если требуется создавать приоритетные потоки или устанавливать приоритеты потоков. Потоки, помещенные в пул, всегда являются фоновыми потоками с обычным уровнем приоритета (ThreadPriority.Normal).
• Если требуется создать поток с фиксированным идентификатором, чтобы име-лаcь возможность завершить, приостановить или обнаружить его по имени.
Исходный код. Проект ThreadPoolApp размещён в подкаталоге, соответствующем главе 14.
На этом наш экскурс в многопоточное программирование .NET завершается. Пространство имен System.Threading, без сомнения, определяет множество других типов, кроме тех, которые смогли уместиться в рамках обсуждения данной главы. Но сейчас вы имеете прочный фундамент, который позволит вам расширять свой знания.