Поток (thread) – это независимая последовательность инструкций в программе. Самый простой способ создания потоков – вызов делегата асинхронным образом.
static int TestThread(int data, int ms)
{
Console.WriteLine("TestThread started");
Thread.Sleep(ms);
Console.WriteLine("TestThread completed");
return ++data;
}
public delegate int TestThreadDelegate(int data, int ms);
Есть несколько способов узнать завершил ли делегат свою работу.Это можно сделать с помощью метода BeginInvoke(), в котором входные параметры можно передать вместе с типом делегата. Этот метод возвращает тип IAsyncResult, у которого есть свойство IsComleted. Вторым способом ожидания результата является использование дескриптора ожидания. Получить к нему доступ можно с помощью свойства AsyncWaitHanle. Третьим способом является использование обратного асинхронного вызова:
static void Main()
{
TestThreadDelegate d1 = TestThread;
d1.BeginInvoke(1, 3000, TestThreadCompleted, d1);
for (int i = 0; i < 100; i++)
{
Console.Write(".");
Thread.Sleep(50);
}
}
static void TestThreadCompleted(IAsyncResult ar)
{
if (ar == null) throw new ArgumentNullException("ar");
TestThreadDelegate d1 = ar.AsyncState as TestThreadDelegate;
Trace.Assert(d1 != null, "Invalid object type");
int result = d1.EndInvoke(ar);
Console.WriteLine("result: {0}", result);
}
Другим способом создания потоков является использование класса Thread. Он также позволяет управлять ими.
using System;
using System.Threading;
namespace Csharp.Threading.FirstThread
{
class Program
{
static void Main(string[] args)
{
Thread t1 = new Thread(ThreadMain);
t1.Start();
Console.WriteLine("This is the main thread.");
}
static void ThreadMain()
{
Console.WriteLine("In thread.");
}
}
}
Передавать данные потокам можно двумя способами: используя конструктор Thread с делегатом ParameterizedThreadStart, либо путем создания специального класса и определения метода потока, как метода экземпляра:
public class MyThread
{
private string data;
public MyThread(string data)
{
this.data = data;
}
public void ThreadMain()
{
Console.WriteLine("Running in a thread, data: {0}", data);
}
}
В Main:
MyThread obj = new myThread(“text”);
Thread tr = new Thread(obj.ThreadMain);
tr.Start();
Существует два типа потоков: приоритетный и фоновый. Процесс продолжает выполняться до тех пор, пока выполняется хотя бы один приоритетный поток. С помощью класса Thread по умолчанию создается именно он. Чтобы поток был фоновым нужно использовать свойство IsBackground.
Операционная система планирует порядок выполнения потоков. На этот процесс можно влиять путем назначения потоку соответствующего приоритета с помощью свойства Priority.
Иногда нужно заранее создать набор потоков, также увеличивать или уменьшать этот набор при возникновении необходимости. Для этого предусмотрен класс ThreadPool.
using System;
using System.Threading;
namespace Csharp.Threading.Pools
{
class Program
{
static void Main()
{
for (int i = 0; i < 5; i++)
{
ThreadPool.QueueUserWorkItem(JobForAThread);
}
Thread.Sleep(5000);
}
static void JobForAThread(object state)
{
for (int i = 0; i < 3; i++)
{
Console.WriteLine("loop {0}, running inside pooled thread {1}", i,
Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(10);
}
}
}
}
Но у пулов потоков есть некоторые ограничения: они являются фоновыми, также менять приоритет или имя потока в пуле нельзя.
Для начала это все. В следующий раз мы поговорим о взаимоблокировке и синхронизации потоков.