Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Пособие КНЕУ.doc
Скачиваний:
24
Добавлен:
07.03.2016
Размер:
3.9 Mб
Скачать

10.3. Багатопотокові додатки

Додаток .NET складається з одного або декількох процесів. Процесу належать виділена для нього область оперативної пам'яті і ресурси. Кожен процес може складатися з декількох доменів (частин) додатків, ресурси яких ізольовані один від одного. В рамках домена може бути запущене декілька потоків виконання. Потоком (thread) є частина виконуваного коду програми. У кожному процесі є первинний потік, виконуючий роль точки входу в додаток. Для консольних застосувань це метод Main.

Багатопотокові застосування створюють як для багатопроцесорних, так і для однопроцесорних систем. Основною метою при цьому є підвищення загальної продуктивності і скорочення часу реакції додатку. Управління потоками здійснює операційна система. Кожен потік отримує деяку кількість квантів часу, після закінчення якого управління передається іншому потоку. Це створює у користувача однопроцесорної машини враження одночасної роботи декількох потоків і дозволяє, наприклад, виконувати введення тексту одночасно з тривалою операцією по передачі даних.

Недоліки багатопоточності:

  • велика кількість потоків веде до збільшення накладних витрат, пов'язаних з їх перемиканням, яке знижує загальну продуктивність системи;

  • у багатопотокових застосуваннях виникають проблеми синхронізації даних, що пов'язані з доступом до одних і тих же даних з боку декількох потоків.

10.3.1. Клас Thread

Підтримка багатопоточності здійснюється в .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

00

-1 -21

-3 -42

-53

4

5

У лістингу використовується метод 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. Формат оператора: