Підтримка багатопоточності здійснюється в .NET в основному за допомогою простору імен System.Threading. Деякі типи цього простору описані в таблиці 10.1
Таблиця 10.1.
Деякі типи простору імен System.Threading
Тип
| Опис
|
Interlocked
| Клас, що забезпечує синхронізований доступ до змінних, які використовуються в різних потоках
|
Monitor
| Клас, що забезпечує синхронізацію доступу до об'єктів
|
Mutex
| Клас-примітив синхронізації, який використовується також для синхронізації між процесами
|
ReaderWriterLock
| Клас, що визначає блокування, що підтримує один доступ на запис і декілька, - на читання
|
Thread
| Клас, який створює потік, встановлює його пріоритет, отримує інформацію про стан
|
ThreadPool
| Клас, використовуваний для управління набором взаємозв'язаних потоків, - пулом потоків
|
Timer
| Клас, що визначає механізм виклику заданого методу в задані інтервали часу для пулу потоків
|
Продовження таблиці 10.1
Тип
| Опис
|
WaitHandle
| Клас, що інкапсулює об'єкти синхронізації, які чекають доступу до ресурсів, що розділяються
|
IOCompletionCallback
| Клас, одержуючий зведення про операцію введення-виведення, що завершилася
|
ThreadStart
| Делегат, що представляє метод, який має бути виконаний при запуску потоку
|
TimerCallback
| Делегат, що представляє метод, оброблювальний виклики від класу Timer
|
WaitCanback
| Делегат, що представляє метод для елементів класу Threadpool
|
ThreadPriority
| Перелічення, що описує пріоритет потоку
|
ThreadState
| Перелічення, що описує стан потоку
|
Первинний потік створюється автоматично. Для запуску вторинних потоків використовується клас Thread. При створенні об'єкту-потоку йому передається делегат, що визначає метод, виконання якого виділяється в окремий потік:
Thread t = new Thread ( new ThreadStart( ім'я_методу ) ) ;
Після створення потоку заданий метод починає в ньому свою роботу, а первинний потік продовжує виконуватися. У лістингу 10.10 приведений приклад одночасної роботи двох потоків.
Лістинг 10.10. Створення вторинного потоку
using System;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static public void Hedgehog() // метод для вторинного потоку
{
for (int i = 0; i < 6; ++i)
{
Console.WriteLine(i);
Thread.Sleep(1000);
}
}
static void Main()
{
Console.WriteLine( "Первинний потік " +
Thread.CurrentThread.GetHashCode());
Thread ta = new Thread(new ThreadStart(Hedgehog) );
Console.WriteLine("Вторинний потік " + ta.GetHashCode() );
ta.Start();
for ( int i = 0; i > -6; --i )
{
Console.Write( " " + i );
Thread.Sleep( 400 );
}
}
}
}
Результат роботи програми:
Первинний потік 1
Вторинний потік 3
-1 -21
-3 -42
-53
У лістингу використовується метод Sleep, що зупиняє функціонування потоку на задану кількість мілісекунд. Як бачите, обидва потоки працюють одночасно. Якби вони працювали з одним і тим же файлом, він був би зіпсований так само, як і приведене виведення на консоль, тому такий спосіб розпаралелювання обчислень має сенс тільки для роботи з різними ресурсами.
У таблиці 10.2 перераховані основні елементи класу Thread.
Таблиця 10.2.
Основні елементи класу Thread
Елемент
| Вигляд
| Опис
|
CurrentThread
| Статична властивість
| Повертає посилання на потік, що виконується (тільки для читання)
|
IsAlive
| Властивість
| Повертає true або false залежно від того, запущений потік чи ні
|
IsBackground
| Властивість
| Повертає або встановлює значення, яке показує, чи є цей потік фоновим
|
Name
| Властивість
| Установка текстового імені потоку
|
Priority
| Властивість
| Отримати/встановити пріоритет потоку (використовуються значення перелічення ThreadPrority)
|
ThreadState
| Властивість
| Повертає стан потоку (використовуються значення перелічення ThreadState)
|
Abort
| Метод
| Генерує виключення ThreadAbortException. Виклик цього методу зазвичай завершує роботу потоку
|
GetData, SetData
| Статичні методи
| Повертає (встановлює) значення для вказаного слота в поточному потоці
|
Продовження таблиці 10.2
Елемент
| Вигляд
| Опис
|
GetDomain, GetDomainID
| Статичні методи
| Повертає посилання на домен додатку (ідентифікатор домена додатку), в рамках якого працює потік
|
GetHashCode
| Метод
| Повертає хеш-код для потоку
|
Sleep
| Статичний метод
| Припиняє виконання поточного потоку на задану кількість мілісекунд
|
Interrupt
| Метод
| Перериває роботу поточного потоку
|
Join
| Метод
| Блокує викликаючий потік до завершення іншого потоку або вказаного проміжку часу і завершує потік
|
Resume
| Метод
| Відновлює роботу після припинення потоку
|
Start
| Метод
| Починає виконання потоку, визначеного делегатом ThreadStart
|
Suspend
| Метод
| Припиняє виконання потоку. Якщо виконання потоку вже припинене, то ігнорується
|
Можна створити декілька потоків, які спільно використовуватимуть один і той же код. Приклад приведений в лістингу 10.11.
Лістинг 10.11. Потоки, що використовують один об'єкт
using System;
using System.Threading;
namespace ConsoleApplication1
{
class Classl
{
public void Do()
{
for ( int i = 0; i < 4; ++i )
{
Console.Write( " " + i ); Thread.Sleep( 3 );
}
}
}
class Program
{
static void Main()
{
Classl a = new Classl();
Thread tl = new Thread( new ThreadStart(a.Do));
tl.Name = "Second";
Console.WriteLine("Потік " + tl.Name );
tl.Start();
Thread t2 = new Thread( new ThreadStart( a.Do));
t2.Name = "Third";
Console.WriteLine( "Потік " + t2.Name);
t2.Start();
}
}
}
Результат роботи програми:
Потік Second
Потік Third
0 0 1 1 2 2 3 3
Варіанти виведення можуть декілька розрізнятися, оскільки один потік перериває виконання іншого в невідомі моменти часу.
Для того, щоб блок коду міг використовуватися в кожен момент тільки одним потоком, застосовується оператор lock. Формат оператора: