Язык программирования C#9 и платформа .NET5
{Lowest,BelowNormal,Normal, // Стандартное значение.AboveNormal,Highest}В случае присваивания уровню приоритета потока значения, отличающегося от стандартного(
), помните об отсутствии прямого контроля над тем, когда планировщик потоков будет переключать потоки между собой. Уровень приоритета потока предоставляет среде .NET Core Runtime лишь подсказку относительно важности действия потока. Таким образом, поток с уровнем приоритетаThreadPriority.Normalне обязательно гарантированно получит наивысший приоритет.ThreadPriority.HighestОпять-таки, если планировщик потоков занят решением определенной задачи (например, синхронизацией объекта, переключением потоков либо их перемещением), то уровень приоритета, скорее всего, будет соответствующим образом изменен. Однако при прочих равных условиях среда .NET Core Runtime прочитает эти значения и проинструктирует планировщик потоков о том, как лучше выделять кванты времени. Потоки с идентичными уровнями приоритета должны получать одинаковое количество времени на выполнение своей работы.
В большинстве случаев необходимость в прямом изменении уровня приоритета потока возникает редко (если вообще возникает). Теоретически можно так повысить уровень приоритета набора потоков, что в итоге воспрепятствовать выполнению низкоприоритетных потоков с их запрошенными уровнями (поэтому соблюдайте осторожность).
Ручное создание вторичных потоков
Когда вы хотите программно создать дополнительные потоки для выполнения какой-то единицы работы, то во время применения типов из пространства имен
следуйте представленному ниже предсказуемому процессу.System.Threading1. Создать метод, который будет служить точкой входа для нового потока.
2. Создать новый делегат
(илиParametrizedThreadStart), передав его конструктору адрес метода, который был определен на шаге 1.ThreadStart3. Создать объект
, передав конструктору в качестве аргумента делегатThread.ParametrizedThreadStart/Threadstart4. Установить начальные характеристики потока (имя, приоритет и т.д.).
5. Вызвать метод
, что приведет к как можно более скорому запуску потока для метода, на который ссылается делегат, созданный на шаге 2.Thread.Start()Согласно шагу 2 для указания на метод, который будет выполняться во вторичном потоке, можно использовать два разных типа делегата. Делегат
способен указывать на любой метод, который не принимает аргументов и ничего не возвращает. Такой делегат может быть полезен, когда метод предназначен просто для запуска в фоновом режиме без дальнейшего взаимодействия с ним.ThreadStartОграничение
связано с невозможностью передавать ему параметры для обработки. Тем не менее, тип делегатаThreadStartпозволяет передать единственный параметр типаParametrizedThreadStart. Учитывая, что с помощьюSystem.Objectпредставляется все, что угодно, посредством специального класса или структуры можно передавать любое количество параметров. Однако имейте в виду, что делегатыSystem.ObjectиThreadStartмогут указывать только на методы, возвращающиеParametrizedThreadStart.voidРабота с делегатом ThreadStart
Чтобы проиллюстрировать процесс построения многопоточного приложения (а также его полезность), создайте проект консольного приложения по имени
, которое позволит конечному пользователю выбирать, будет приложение выполнять свою работу в единственном первичном потоке или же разделит рабочую нагрузку с применением двух отдельных потоков выполнения.SimpleMultiThreadAppПосле импортирования пространства имен
определите метод для выполнения работы (возможного) вторичного потока. Чтобы сосредоточиться на механизме построения многопоточных программ, этот метод будет просто выводить на консоль последовательность чисел, делая на каждом шаге паузу примерно в 2 секунды. Ниже показано полное определение классаSystem.Threading:Printerusing System;using System.Threading;namespace SimpleMultiThreadApp{public class Printer{public void PrintNumbers(){// Вывести информацию о потоке.Console.WriteLine("-> {0} is executing PrintNumbers()",Thread.CurrentThread.Name);// Вывести числа.Console.Write("Your numbers: ");for(int i = 0; i < 10; i++){Console.Write("{0}, ", i);Thread.Sleep(2000);}Console.WriteLine();}}}Добавьте в файл
операторы верхнего уровня, которые предложат пользователю решить, сколько потоков будет использоваться для выполнения работы приложения: один или два. Если пользователь запрашивает один поток, то нужно просто вызвать методProgram.csв первичном потоке. Тем не менее, когда пользователь выбирает два потока, понадобится создать делегатPrintNumbers(), указывающий наThreadStart, передать объект делегата конструктору нового объектаPrintNumbers()и вызвать методThreadдля информирования среды .NET Core Runtime о том, что данный поток готов к обработке. Вот полная реализация:Start()using System;using System.Threading;using SimpleMultiThreadApp;