Визначення стану потоку

880 Частина II. Бібліотека C #

Якщо в даному прикладі програми метод Abort () викликається з нульовим аргументом, то запит на передчасне переривання скасовується потоком, що викликає метод ResetAbort (). і виконання цього потоку триває. Будь-яке інше значен ня аргументу призведе до переривання потоку.

Призупинення та відновлення потоку

У початкових версіях середовища .NET Framework потік можна було пріостано- вити викликом методу Thread.Suspend () і відновити викликом методу Thread. Resume (). Але тепер обидва ці методи вважаються застарілими і не рекомендуються до застосування в новому коді. Пояснюється це, зокрема, тим, що користуватися мето- будинок Suspend () насправді небезпечно, так як з його допомогою можна пріостано- вити потік, який в даний момент утримує блокування, що перешкоджає її зняття, а отже, призводить до взаімоблокіровке . Застосування обох мето- дов може стати причиною серйозних ускладнень на рівні системи. Тому для припинення та поновлення потоку слід використовувати інші засоби сінхро- нізації, в тому числі м'ютекс і семафор.

Стан потоку може бути отримано з властивості ThreadState, доступного в класі Thread. Нижче наведена загальна форма цієї властивості.

public ThreadState ThreadState

Стан потоку повертається у вигляді значення, визначеного в перерахуванні ThreadState. Нижче наведені значення, визначені в цьому переліку.

Всі ці значення не вимагають особливих пояснень, за винятком одного. Значення ThreadState.WaitSleepJoin позначає стан, в яке потік переходить під час очікування в зв'язку з викликом методу Wait (), Sleep () або Join ().

Застосування основного потоку

Як пояснювалося в самому початку цієї глави, у будь-якої програми на C # є хоча б один потік виконання, званий основним. Цей потік програма отримує автоматично, як тільки починає виконуватися. З основним потоком можна обра- тися таким же чином, як і з усіма іншими потоками.

Для доступу до основного потоку необхідно отримати об'єкт типу Thread, кото-рий посилається на нього. Це робиться за допомогою властивості CurrentThread, являющего- ся членом класу Thread. Нижче наведена загальна форма цієї властивості.

public static Thread CurrentThread

Глава 23. Багатопотокове програмування. Частина перша: основи

Дана властивість повертає посилання на той потік, в якому воно використовується. По- цьому якщо властивість CurrentThread використовується при виконанні коду в основному потоці, то з його допомогою можна отримати посилання на основний потік. Маючи в своєму розпорядженні таку посилання, можна управляти основним потоком так само, як і будь- яким іншим потоком.

// Продемонструвати управління основним потоком.

class UseMain // Отримати основний потік. Thrd = Thread.CurrentThread;

// Показати ім'я основного потоку. if (Thrd.Name == null)

Console.WriteLine ( "У основного потоку немає імені."); else

Console.WriteLine ( "Основний потік називається:" + Thrd.Name);

// Показати пріоритет основного потоку.

// Встановити ім'я і пріоритет. Console.WriteLine ( "Установка імені та пріоритету. \ N"); Thrd.Name = "Основний Потік";

Console.WriteLine ( "Тепер основний потік називається:" + Thrd.Name);

Console.WriteLine ( "Тепер пріоритет:" + Thrd.Priority);

Нижче наведено результат виконання цієї програми.

У основного потоку немає імені. Пріоритет: Normal

Установка імені та пріоритету.

Тепер основний потік називається: Основний Потік Тепер пріоритет: AboveNormal

Слід, однак, бути дуже уважним, виконуючи операції з основним пото- ком. Так, якщо додати в кінці методу Main () наступний виклик методу Join ():

програма ніколи не завершиться, оскільки вона буде чекати закінчення основного потоку!

882 Частина II. Бібліотека C #

Додаткові кошти багатопотокової обробки, впроваджені в версії .NET Framework 4.0

У версії .NET Framework 4.0 впроваджений ряд нових засобів многопоточной обробки, які можуть виявитися дуже корисними. Найважливішим серед них є нова система скасування. У цій системі підтримується механізм скасування потоку простим, цілком визначеним і структурованим способом. В основу цього механізму по- ложено поняття ознаки скасування, за допомогою якого вказується стан скасування потоку. Ознаки скасування підтримуються в класі CancellationTokenSource і в структурі CancellationToken. Система скасування повністю інтегрована в нову бібліотеку розпаралелювання завдань (TPL), і тому вона докладніше рассматрівает- ся разом з TPL в главі 24.

public static bool Yield ()

Цей метод повертає логічне значення true, якщо відбувається перемикання контексту. За відсутності іншого потоку, готового для виконання, перемикання кон- тексту не відбудеться.

Рекомендації по багатопоточн програмування

Запуск окремого завдання

Багатозадачність на основі потоків найчастіше організовується при программірова- ванні на С #. Але там, де це доречно, можна організувати і багатозадачність на основі процесів. У цьому випадку замість запуску іншого потоку в одній і тій же програмі

Глава 23. Багатопотокове програмування. Частина перша: основи 883

одна програма починає виконання іншої. При програмуванні на C # це робиться за допомогою класу Process, визначеного в просторі імен System. Diagnostics. На закінчення цієї глави коротко будуть розглянуті особливості за- пуску і управління іншим процесом.

Найпростіший спосіб запустити інший процес - скористатися методом Start (). визначеним у класі Process. Нижче наведена одна з найпростіших форм цього методу:

public static Process Start (string имя_файла)

де имя_файла позначає конкретне ім'я файлу, який повинен виконуватися або ж пов'язаний з виконуваним файлом.

public void Close ()

Процес може бути перерваний двома способами. Якщо процес є приложе- ням Windows з графічним призначеним для користувача інтерфейсом, то для переривання такого процесу викликається метод CloseMainWindow (). форма якого наведена нижче.

public bool CloseMainWindow ()

Цей метод посилає процесу повідомлення, що пропонує йому зупинитися. Він повертає логічне значення true, якщо повідомлення отримано, і логічне значення false, якщо програма не має графічного інтерфейсу або головного вікна. Слід, однак, мати на увазі, що метод CloseMainWindow () слу- жит тільки для запиту зупинки процесу. Якщо додаток проігнорує такий запит, то воно не буде перервано як процес.

Для безумовного переривання процесу слід викликати метод Kill (). як пока- зано нижче.

public void Kill ()

Але методом Kill () слід користуватися акуратно, так як він призводить до некон- троліруемому переривання процесу. Будь-які незбережені дані, пов'язані з пре- розриву процесом, будуть, швидше за все, втрачені.

Для того щоб організувати очікування завершення процесу, можна скориста- тися методом WaitForExit (). Нижче наведено дві його форми.

public void WaitForExit ()

public bool WaitForExit (int мілісекунд)

У першій формі очікування триває до тих пір, поки процес не завершиться,

а в другій формі - тільки протягом зазначеного кількості мілісекунд. В остан- ньому випадку метод WaitForExit () повертає логічне значення true, якщо процес завершився, і логічне значення false, якщо він все ще виконується.

884 Частина II. Бібліотека C #

// Продемонструвати запуск нового процесу.

class StartProcess Process newProc = Process.Start ( "wordpad.exe");

Console.WriteLine ( "Новий процес запущений.");

newProc.Close (); // звільнити виділені ресурси

Console.WriteLine ( "Новий процес завершено.");

При виконанні цієї програми запускається стандартний додаток WordPad, і на екрані з'являється повідомлення "Новий процес запущений.". Потім програма очікує закриття WordPad. Після закінчення роботи WordPad на екрані з'являється за- виключне повідомлення "Новий процес завершено." .