Console.WriteLine ("-› {0} выполняет PrintNumbers", Thread.CurrentThread.Name);
// Вывод чисел.
Console.Write("Ваши числа: ");
for(int i = 0; i ‹ 10; i++) {
Console.Write(i + ", ");
Thread.Sleep(2000);
}
Console.WriteLine;
}
}
Теперь в Main нужно предложить выбор одного или двух потоков для выполнения задач приложения. Если пользователь выберет использование одного потока, просто вызывается метод PrintNumbers в рамках первичного потока. Но если пользователь указывает два потока, создается делегат ThreadStart, указывающий на PrintNumbers. Объект делегата передается конструктору нового объекта Thread и вызывается метод Start, информирующий среду CLR о том, что поток готов к обработке.
Сначала установите ссылку на компоновочный блок System.Windows.Forms.dll и с помощью MessageBox.Show отобразите подходящее сообщение в Main (смысл этого станет ясным при запуске программы). Вот полная реализация Main в нужном виде.
static void Main(string[] args) {
Console.WriteLine("
Console.Write("Хотите иметь [1] или [2] потока?");
string threadCount = Console.ReadLine;
// Имя текущего потока.
Thread primaryThread = Thread.CurrentThread;
primaryThread.Name = "Первичный";
// Вывод информации Thread.
Console.WriteLine("-› {0} выполняет Main", Thread.CurrentThread.Name);
Printer р = new Printer;
switch (threadCount) {
case "2":
// Теперь создание потока.
Thread backgroundThread = new Thread(new ThreadStart(p.PrintNumbers));
backgroundThread.Name = "Вторичный";
backgroundThread.Start;
break;
case "1":
p.PrintNumbers;
break;
default:
Console.WriteLine("Ваши указания не ясны… будет 1 поток.");
goto case "1";
}
// Выполнение дополнительней работы.
MessageBox.Show("Я занят!", "Работа в главном потоке…");
Console.RеаdLine;
}
Если теперь запустить эту программу с одним потоком, вы обнаружите, что окно сообщения не будет отображено до тех пор, пока на консоль не будет выведена вся последовательность чисел. Здесь была указана пауза приблизительно в две секунды после вывода каждого из чисел, поэтому подобное поведение программы не вызовет восхищения конечного пользователя. Но если вы выберете вариант с двумя потоками, окно сообщения появится немедленно, поскольку для вывода чисел на консоль будет использоваться свой уникальный объект Thread (рис. 14.7).
Рис. 14.7. Многопоточные приложения "более отзывчивы" при выдаче своих результатов
Здесь важно отметить, что при построении многопоточных приложений (с применением асинхронных делегатов) на машинах с одним процессором вы не получаете приложение,
Исходный код. Проект SimpleMultiThreadApp размещен в подкаталоге, соответствующем главе 14.
Работа с делегатом ParameterizedThreadStart
Напомним, что делегат ThreadStart может указывать только на методы, возвращающие void и не имеющие аргументов. Во многих случаях этого будет вполне достаточно, но передать данные методу, выполняющемуся во вторичном потоке, вы сможете только с помощью делегата ParameterizedThreadStart. Для примера воссоздадим программную логику проекта AsyncCallbackDelegate, построенного в этой главе выше, но на этот раз используем тип делегата ParameterizedThreadStart.