|
|||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||
|
Створення
потоків
Почнемо з
елементарного прикладу. Допустимо, ви
хочете запустити в окремому
потоці процедуру, яка в
нескінченному циклі зменшує
значення лічильника. Процедура
визначається у складі класу: Public
Class Willusethreads Public Sub Subtractfromcounter() Dim count As Integer Do While True count -= 1 Console.WriteLlne("Am
in another thread and counter =" & count) Loop End Sub End Class
Оскільки умова циклу Do
залишається істинною завжди, можна подумати, що
ніщо не перешкодить
виконанню процедури Subtractfromcounter. Проте в
багатопотоковому застосуванні це не
завжди так. У наступному фрагменті
приведена процедура Sub Main,
що запускає потік, і команда
Imports: Option Strict On
Imports System.Threading Module Modulel Sub Main() 1 Dim mytest As New
Willusethreads() 2 Dim bthreadstart As New Threadstart(Addressof _ mytest.SubtractFromCounter) 3 Dim bthread As New
Thread(bthreadstart) 4 ' bthread.Start() Dim i As
Integer 5 Do
While True Console.WriteLine("In main thread and count is " & i) i += 1 Loop End Sub End Module Давайте послідовно розберемо найбільш
принципові моменти. Перш
за все процедура
Sub Man n завжди працює в
головному потоці (main thread). У
програм-мах .NET завжди працюють мінімум
два потоки: головний і
потік збірки сміття. У рядку 1
створюється новий екземпляр тестового класу.
У рядку 2 ми створюємо делегат
Threadstart і передаємо адресу процедури
Subtractfromcounter екземпляра тестового
класу, створеного в
рядку 1 (ця процедура викликається без
параметрів). Завдяки імпортуванню
простору імен
Threading довге ім'я можна не
указувати. Об'єкт нового потоку створюється
в рядку 3. Звернете увагу
на передачу делегата Threadstart
при виклику конструктора класу
Thread. Деякі програмісти вважають
за краще
об'єднувати ці два рядки в один
логічний рядок: Dim bthread As New Thread(New Threadstarttaddressof _ mytest.SubtractFromCounter)) Нарешті, рядок
4 «запускає» потік, для чого
викликається метод Start екземпляра
класу Thread, створеного для делегата
Threadstart. Викликаючи цей метод, ми
указуємо операційній системі,
що процедура Subtract повинна працювати
в окремому потоці.
На мал. 10.1
показаний приклад того, що може
відбутися після запуску програми
і її подальшого переривання
клавішею Ctrl+break. У нашому випадку
новий потік запустився лише після
того, як лічильник в головному потоці
збільшився до 341!
Мал. 10.1. Проста
багатопотокова програмно час роботи
Якщо програма працюватиме протягом
большегошромежутка часу,
результат виглядатиме приблизно так,
як показано на мал. 10.2. Ми бачимо,
що виконання запущеного потоку
припиняється і управління
знову передається головному
потоку. В даному випадку має
місце прояв витісняючої мно-гопоточності
за допомогою
квантування часу. Сенс цього
страхітливого терміну роз'яснюється
нижче.
Мал. 10.2. Перемикання між
потоками в простій багатопотоковій програмі При перериванні потоків і передачі
управління іншим потокам операційна
система використовує принцип
витісняючої багатопоточності за
допомогою квантування
часу. Квантування часу
також вирішує одну з
поширених проблем, що виникали
раніше в багатопотокових програмах,
— один потік займає весь
процесорний час і не поступається
управлінням іншим потокам (як
правило, це трапляється в інтенсивних
циклах на зразок
приведеного вище). Щоб
запобігти монопольному захопленню
процесора, ваші потоки повинні
час від часу передавати
управління іншим потокам. Якщо
програма виявиться «несвідомою»,
існує інше, трохи менш
бажане рішення: операційна
система завжди витісняє
працюючий потік незалежно від
рівня його пріоритету, щоб доступ
до процесора був наданий
кожному потоку в системі.
Якщо включити наступний
рядок в нашу програму перед
викликом Start, то навіть потоки, що
володіють мінімальним
пріоритетом, отримають деяку
частку процесорного часу: bthread.Priority =
Threadpriority.Highest
Мал. 10.3. Потік з
максимальним пріоритетом зазвичай починає працювати швидше
Мал. 10.4. Процесор
надається і потокам з нижчим пріоритетом Команда
призначає новому потоку
максимальний пріоритет і зменшує
пріоритет головного потоку. З мал. 10.3
видно, що новий потік починає
працювати швидше, ніж раніше, але,
як показує мал. 10.4, головний
потік теж отримує управління (правда,
дуже ненадовго і лише після
тривалої роботи потоку з
відніманням). При запуску програми
на ваших комп'ютерах будуть
отримані результати, схожі на
показаних на мал. 10.3 і 10.4, але із-за
відмінностей між нашими системами
точного збігу не буде. У перераховуваний
тип Threadprlority входять значення для
п'яти рівнів пріоритету: Threadpriority.Highest Threadpriority.AboveNormal Threadprlority.Normal
Threadpriority.BelowNormal Threadpriority.Lowest
|
|
|||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||