Чтобы проиллюстрировать процесс построения многопоточного приложения (а также его полезность), создайте проект консольного приложения по имени SimpleMultiThreadApp, которое позволит конечному пользователю выбирать, будет приложение выполнять свою работу в единственном первичном потоке или же разделит рабочую нагрузку с применением двух отдельных потоков выполнения.
После импортирования пространства имен System.Threading определите метод для выполнения работы (возможного) вторичного потока. Чтобы сосредоточиться на механизме построения многопоточных программ, этот метод будет просто выводить на консоль последовательность чисел, делая на каждом шаге паузу примерно в 2 секунды. Ниже показано полное определение класса Printer:
using 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 и вызвать метод Start() для информирования среды .NET Core Runtime о том, что данный поток готов к обработке. Вот полная реализация:
using System;
using System.Threading;
using SimpleMultiThreadApp;
Console.WriteLine("***** The Amazing Thread App *****\n");
Console.Write("Do you want [1] or [2] threads? ");
string threadCount = Console.ReadLine(); // Запрос количества потоков
// Назначить имя текущему потоку.
Thread primaryThread = Thread.CurrentThread;
primaryThread.Name = "Primary";
// Вывести информацию о потоке.
Console.WriteLine("-> {0} is executing Main()",
Thread.CurrentThread.Name);
// Создать рабочий класс.
Printer p = new Printer();
switch(threadCount)
{
case "2":
// Создать поток.
Thread backgroundThread =
new Thread(new ThreadStart(p.PrintNumbers));
backgroundThread.Name = "Secondary";
backgroundThread.Start();
break;
case "1":
p.PrintNumbers();
break;
default:
Console.WriteLine("I don't know what you want...you get 1 thread.");
goto case "1"; // Переход к варианту с одним потоком
}
// Выполнить некоторую дополнительную работу.
Console.WriteLine("This is on the main thread, and we are finished.");
Console.ReadLine();
Если теперь вы запустите программу с одним потоком, то обнаружите, что финальное окно сообщения не будет отображать сообщение, пока вся последовательность чисел не выведется на консоль. Поскольку после вывода каждого числа установлена пауза около 2 секунд, это создаст не особенно приятное впечатление у конечного пользователя. Однако в случае выбора двух потоков окно сообщения отображается немедленно, потому что для вывода чисел на консоль выделен отдельный объект Thread.
Работа с делегатом ParametrizedThreadStart