- •3. Многопоточность
- •Создание нескольких потоков в конструкторе класса и синхронизация их завершения.
- •Thread - класс
- •Потокобезопасность: этот тип можно безопасно использовать в многопоточных операциях. Примечания
- •Thread - члены Открытые конструкторы
- •Открытые свойства
- •Открытые методы
- •Защищенные методы
- •ThreadState - перечисление
- •Примечания
- •Требования
- •См. Также
3. Многопоточность
Как было сказано, все процессы имеют, по крайней мере, один поток управления, который обычно называется стартовым или основным.
Поток может находиться в одном из нескольких возможных состояний:
-
Он может выполняться.
-
Он может быть готовым к выполнению. Выполняющийся поток может быть приостановлен, т.е. его выполнение временно прекращается. Позже оно может быть возобновлено.
-
Поток может быть заблокирован в ожидании необходимого ресурса.
-
Наконец, поток может завершиться, и уж в этом случае его выполнение окончено и продолжению (возобновлению) не подлежит.
В среде .NET Framework определено два типа потоков: высокоприоритетный (foreground) и низкоприоритетный, или фоновый (background). По умолчанию поток создается высокоприоритетным, но его тип можно изменить, т.е. сделать его фоновым.
Единственное различие между высоко- и низкоприоритетным потоками состоит в том, что последний будет автоматически завершен, если все высокоприоритетные потоки в его процессе остановились.
Поточно-ориентированная многозадачность не может обойтись без специального средства, именуемого синхронизацией, которое позволяет координировать выполнение потоков вполне определенными способами. В С# предусмотрена отдельная подсистема, посвященная синхронизации.
Создание потока
В классе Thread пространства имен System.Threading определен ряд методов и свойств для управления потоками.
Чтобы создать поток, необходимо создать объект типа Thread. В классе Thread определен следующий конструктор:
public Thread ( ThreadStart entryPoint )
Здесь:
Параметр еntryPoint содержит имя метода, который будет вызван, чтобы начать выполнение потока (команд).
Тип ThreadStart — это делегат, определенный в среде .NET Framework:
public delegate void ThreadStart ()
Метод, представляющий поток, должен иметь тип возвращаемого значения void и не принимать никаких аргументов.
Пример:
Thread t2 = new Thread (new ThreadStart (Method) );
Для запуска потока на выполнение необходимо вызвать метод Start(), который определяется в классе Thread:
public void Start()
После выхода из entryPolnt-метода выполнение потока автоматически завершается.
Пример.
t2.Start();
Метод Sleep() приостановливает выполнение потока, из которого он был вызван, на период времени, заданный в миллисекундах.
public static void Sleep ( int milliseconds )
Пример 1. Создание нового потока на базе статического метода
using System;
using System.Threading;
class Class1
{
// Дочерний поток. Метод Coundown считает от 1 до 1000
public static void Method ()
{
for ( int i = 1; i <= 10000; i++)
Console.Write (i + " ");
}
// Стартовый поток
static void Main()
{
// Создание второго потока
// ThreadStart dlg = new ThreadStart(Method));
// Thread t2 = new Thread (dlg );
Thread t2 = new Thread (new ThreadStart (Method) );
// Запуск потока
t2.Start();
// В это же время метод Method вызывается в основном потоке
Method();
Console.ReadLine();
}
}
Пример 2. Создание нового потока на базе динамического метода
using System;
using System.Threading;
class Class1
{
public int count;
private string thrdName;
public Class1(string name)
{
count = 0;
thrdName = name;
}
// Начало (входная точка) потока.
public void Run()
{
Console.WriteLine (thrdName + " стартовал.");
do
{
Console.Write ("#");
Thread.Sleep(300);
} while (++count < 10);
Console.WriteLine ("\n" + thrdName + " завершен.");
}
}
class MultiThread
{
public static void Main()
{
Console.WriteLine ("Основной поток стартовал.");
// Сначала создаем объект класса Class1.
Class1 mt = new Class1 ("Дочерний поток");
// Затем из метода этого объекта создаем поток.
Thread newThrd = new Thread (new ThreadStart(mt.Run));
newThrd.Start(); // Запускаем выполнение потока.
do
{
Console.Write(".");
Thread.Sleep (200);
} while (mt.count != 10);
Console.WriteLine ("Основной поток завершен.");
}
}
В VS 2005 возможен вызов параметризированного конструктора Thread без делегата. Благодаря такой возможности можно запускать поток, передавая ему параметр в методе Start():
using System;
using System.Threading;
public class Work
{
public static void Main()
{
// To start a thread using a shared thread procedure, use the class name and
// method name when you create the ParameterizedThreadStart delegate.
// C# infers the appropriate delegate creation syntax:
// new ParameterizedThreadStart(Work.DoWork)
Thread newThread = new Thread(Work.DoWork);
// Thread newThread = new Thread(new ParameterizedThreadStart(Work.DoWork));
// Use the overload of the Start method that has a parameter of type Object.
// You can create an object that contains several pieces of data, or you can pass
// any reference type or value type.
// The following code passes the integer value 42.
newThread.Start(42);
// To start a thread using an instance method for the thread
// procedure, use the instance variable and method name when
// you create the ParameterizedThreadStart delegate.
// C# infers the appropriate delegate creation syntax:
// new ParameterizedThreadStart(w.DoMoreWork)
Work w = new Work();
newThread = new Thread(w.DoMoreWork);
// Pass an object containing data for the thread.
newThread.Start("The answer.");
}
public static void DoWork(object data)
{
Console.WriteLine("Static thread procedure. Data='{0}'", data);
}
public void DoMoreWork(object data)
{
Console.WriteLine("Instance thread procedure. Data='{0}'", data);
}
}
/* This code example produces the following output (the order
of the lines might vary):
Static thread procedure. Data='42'
Instance thread procedure. Data='The answer'
*/
Если метод Start содержит параметр, то и вызываемый метод должен быть определен с параметром типа object.