|
|||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||
|
Метод Join
Іноді
програмний потік потрібно
припинити до моменту
завершення іншого потоку.
Допустимо, ви хочете припинити
потік 1 до тих пір, поки потік 2 не
завершить свої обчислення. Для цього
з потоку 1 викликається метод Join
для потоку 2. Інакше кажучи, команда thread2.Join() припиняє
поточний потік і чекає завершення
потоку 2. Потік 1 переходить в заблокований
стан. Якщо приєднати потік 1 до потоку 2 методом Join, операційна система автоматично запустить потік 1 після завершення потоку 2. Врахуйте, що процес запуску є недетермінованим: не можна точно сказати, через який проміжок часу після завершення потоку 2 запрацює потік 1. Існує і інша версія Join, яка повертає логічну величину: thread2.Join(Integer)
Цей метод або чекає завершення
потоку 2, або розблоковує
потік 1 після
закінчення заданого інтервалу
часу, унаслідок чого
планувальник операційної системи знову
виділятиме потоку процесорний
час. Метод повертає True, якщо
потік 2 завершується до
закінчення заданого інтервалу тайм-ауту, і
False інакше.
Імена потоків,
Currentthread і Threadstate
Перед запуском
кожному потоку рекомендується
привласнити змістовне ім'я,
оскільки імена значно
спрощують відладку багатопотокових
програм. Для цього слід задати
значення властивості Name командою
наступного вигляду: bthread.Name =
"Subtracting thread" Властивість
Thread.CurrentThread повертає посилання на об'єкт
потоку, що виконується зараз. Хоча для
відладки багатопотокових застосувань в
VB .NET існує чудове вікно
потоків, про яке розказано далі,
нас дуже часто виручала команда Msgbox(Thread.CurrentThread.Name) Нерідко
з'ясовувалося, що код виконується
зовсім не в тому потоці, в якому
йому належало виконуватися. Нагадаємо, що термін «недетерміноване
планування програмних
потоків» означає дуже
просту річ: у розпорядженні програміста
практично немає
засобів, що дозволяють
впливати на роботу планувальника.
З цієї причини в програмах
часто використовується властивість
Threadstate, що повертає
інформацію про поточний стан
потоку.
Вікно потоків (Threads
window) Visual Studio .NET надає
неоціниму допомогу у відладці
багатопотокових програм. Воно
активізується командою підміню
Debug > Windows в режимі переривання.
Допустимо, ви призначили ім'я потоку
bthread наступною командою: bthread.Name =
"Subtracting thread" Зразковий вид
вікна потоків після переривання
програми комбінацією клавіш Ctrl+break
(або іншим способом) показаний на мал.
10.5.
Мал. 10.5. Вікно потоків
Стрілкою в
першому стовпці позначається активний
потік, повертаний властивістю Thread.CurrentThread.
Стовпець ID містить числові
ідентифікатори потоків. У
наступному стовпці перераховані
імена потоків (якщо вони були
привласнені). Стовпець Location указує
виконувану процедуру (наприклад,
процедура Writeline класу Console на мал. 10.5).
Решта стовпців містить
інформацію про пріоритет і
припинені потоки (див.
наступний розділ). Вікно потоків (а
не операційна система!) дозволяє
управляти потоками вашої програми
за допомогою контекстних меню.
Наприклад, ви можете зупинити
поточний потік, для чого слід
клацнути у відповідному рядку
правою кнопкою миші і вибрати
команду Freeze (пізніше роботу
зупиненого потоку можна
відновити). Зупинка потоків
часто використовувана при відладці,
щоб неправильно працюючий потік
не заважав роботі додатку. Крім
того, вікно потоків дозволяє
активізувати інший (не
зупинений) потік; для цього
слід клацнути правою кнопкою
миші в потрібному рядку і вибрати в
контекстному меню команду Switch To Thread (або
просто зробити подвійне клацання на
рядку потоку). Як буде показано
далі, це дуже зручно при
діагностиці потенційних
взаємних блокувань (deadlocks).
Тимчасово невживані
потоки можна перевести
в пасивний стан методом
Slєєр. Пасивний потік також вважається
за заблокований.
Зрозуміло, з перекладом потоку в
пасивний стан на долю
решти потоків дістанеться
більше ресурсів процесора.
Стандартний синтаксис методу Slєєр
виглядає таким чином: Thread.Sleep(інтервал_в_міллісекундах) В результаті
виклику Sleep активний потік переходить
в пасивний стан як мінімум
на задану кількість мілісекунд
(втім, активізація відразу ж
після закінчення заданого
інтервалу не гарантується).
Звернете увагу: при виклику
методу посилання на конкретний потік
не передається — метод Sleep
викликається тільки для активного
потоку. Інша версія Sleep
примушує поточний потік поступитися
частиною виділеного процесорного
часу, що залишилася: Thread.Sleep(0) Наступний варіант переводить поточний потік в пасивний стан на необмежений час (активізація відбувається тільки при виклику Interrupt): Thread.Slеер(Timeout.Infinite) Оскільки
пасивні потоки (навіть при
необмеженому часі очікування)
можуть уриватися методом Interrupt,
що приводить до ініціації
виключення Threadlnterruptexcepti on, виклик Slєєр
завжди полягає в блок Try-catch, як
в наступному фрагменті: Try Thread.Sleep(200) Catch
tie As Threadlnterruptedexception ' Пасивний стан потоку був перерваний Catch e
As Exception 'Решта виключень End Try
Завершення або
переривання програмних потоків
Потік автоматично завершується
при виході з методу, вказаного
при створенні делегата Threadstart, але
іноді потрібно завершити метод
(отже, і потік) при
виникненні певних чинників. У
таких випадках в потоках
зазвичай перевіряється умовна змінна,
залежно від стану якої
ухвалюється рішення про аварійний
вихід з потоку. Як правило, для
цього в процедуру включається цикл Do-while: Sub Threadedmethod() ' У
програмі необхідно передбачити засоби для опиту ' умовною
змінною. '
Наприклад, умовну змінну можна оформити у вигляді властивості ' і
використовувати посилання на цю
властивість в програмі. Do While conditionvariable = False And Moreworktodo '
Основний код Loop End Sub
Якщо перевірка
умовної змінної повинна
відбуватися в строго певному
місці, скористайтеся командою If-then
у поєднанні з Exit Sub усередині
нескінченного циклу.
На жаль, код пасивних
(або заблокованих іншим
чином) потоків не виконується,
тому варіант з опитом
умовної змінної для них
не підходить. В цьому випадку слід
викликати метод Interrupt для об'єктної
змінної, що містить
посилання на потрібний потік. Метод Interrupt може
викликатися тільки для потоків,
що знаходяться в стані
Wait, Sleep або Join. Якщо викликати Interrupt для
потоку, що знаходиться в одному
з перерахованих станів, то
через деякий час потік знову
почне працювати, а виконавче
середовище ініціює в потоці
виключення Threadlnterruptedexcepti on. Це відбувається
навіть в тому випадку, якщо потік
був переведений в пасивний стан
на невизначений термін викликом
Thread.Sleepdimeout. Infinite). Ми говоримо «через
деякий час», оскільки
планування потоків має
недетерміновану природу. Виключення Threadlnterruptedexcepti
on перехоплюється секцією
Catch, що містить код виходу
із стану очікування. Проте секція Catch
зовсім не зобов'язана завершувати потік по
виклику Interrupt — потік обробляє
виключення на свій розсуд.
|
|
|||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||