Потоки (Threads)
Коли запускається новий додаток, то для нього автоматично створюється головний потік, в якому буде виконуватися код програми. У будь-який момент можна створити додаткові потоки, які виконуватимуться паралельно головному. Тому будь-яка програма – це завжди один головний потік і нуль або більше допоміжних (не рекомендується створювати більше 16 процесів на однопроцесорному комп'ютері).
Використовувати потоки зручно для різних цілей. Вони дозволяють виконувати завдання у фоновому режимі і дозволяють користувачеві зосередитися на головній роботі.
Для наочного уявлення створимо додаток, що демонструє роботу потоку.
Програма запускає потік натисканням кнопки Запустити та в компоненті TLabel працюватиме лічильник. У цей же час можна без проблем набирати текст у RichEdit

1. Створюємо новий проект. Встановлюємо форму компонентTRichEdit з вкладки Win32 і один компонентTLabel. Ще знадобиться пара кнопок – одна для запуску потоку, інша для його зупинки.
2. Тепер створюємо модуль потоку. Для цього вибираємо пункт менюFile New Other для відкриття вікна створення нового модуля. ВиділитиThread Object та натисніть кнопкуОК. В результаті з'явиться вікно:

3. У цьому вікні потрібно вказати ім'я потоку, що створюється –TCountobj. Натиснути кнопкуОК, і Delphi створить модуль заготівлі для майбутнього потоку. Збережіть весь проект – головну форму під ім'ямMain, потік під ім'ямMyThread.
Об'єкт потоку має лише одну процедуруExecute (заготівля для програмного коду потоку), при його створенні вона оголошена як абстрактна (abstract) - порожня. Це означає, що процедурі дали ім'я, виділили місце у пам'яті, але її коду будь-яких потоках може бути перевизначений, тобто. повинен бути написаний власний код, який виконуватиметься паралельно до основного завдання.
Зміннаindex оголошена якinteger у розділіprivate об'єкта потоку. Там само оголошено процедуруUpdateLabel. Ця процедура виглядає так:
4. Далі в модулі потоку підключаємо головну форму в розділuses, тому що звернення до неї відбувається в коді вище (Form1.Label1.Caption) для оновлення тексту компонентаLabel1. У методіExecute запускається цикл while, який виконуватиметься, доки змінна index більше нуля. Всередині циклу викликається метод synchronize() та збільшується змінна index. Якщо ця змінна стає більше 100 000, то index присвоюється 0 і розрахунок припиняється. Таким чином, цикл нескінченно виконуватиме збільшення змінноїindex від 0 до 100000. Останньою йде перевірка наступного характеру, якщо властивість terminated дорівнює true, то вийти з процедури і робота потоку закінчиться. Властивістьterminated дорівнюватимеtrue тоді, коли буде викликаний методTerminate потоку.
5. Про функціюsynchronize. Як параметр їй передається процедура updateLabel, яка робить висновок у головну форму. Для чого потрібно вставляти процедуру виведення на екран у synchronize? Бібліотека VCL має одну ваду – вона не захищена від потоків. Всі компоненти користувача розроблялися так, що до них може отримати доступ тільки один потік. Якщо головна форма і потік спробують одночасно вивести що-небудь в ту саму область екрана або компонент, то програма впаде. Тому весь висновок на форму потрібно виділяти в окрему процедуру та викликати цю процедуру за допомогою Synchronize.
Якщо процедура викликана у методіSynchronize, то до компонентів вікна отримує доступ лише об'єкт, що викликав метод synchronize. Цей процес є непомітним для користувача.
Таким чином, якщо потрібно вивести якісь дані з потоку на екран головного вікна, то робіть це окремою процедурою і викликайте її за допомогою Методу Synchronize. Потік готовий.
Саме тому додавати модульMyThread потрібно в перший розділuses.
У розділіprivate оголосити змінну типу TCountobj (об'єкт потоку).
Після натискання кнопкиЗапустити написати код:
У першому рядку коду створюється потік з. Як параметр може бути true або false. Якщо false, то потік відразу починає виконання, інакше потік створюється, але не запускається. Якщо потік створений незапушеним, то для запуску потрібно використовувати метод Resume, що відбувається в другому рядку. У третьому рядку встановлюється менший пріоритет потоку, щоб він не заважав роботі основного потоку і виконувався у фоновому режимі. Якщо встановити вище пріоритет, то основний потік почне пригальмовуватися, тому що у них будуть однакові пріоритети.
Для подіїonclick кнопкиЗупинити написати наступний код:
Тут відбувається зупинка виконання потоку за допомогою виклику методуTerminate об'єкта потоку. Після виклику цього методу властивість terminated стане рівним true і виконання процедуриExecute закінчується.
| Досить часто виникає ситуація, коли хочеться приготувати біляші, а часу для клопоту з дріжджовим тестом катастрофічно не вистачає. В цьому випадку дуже доречним буде тісто бездрожжеве на kz.all.biz. |
7. Запускаємо програму, запускаємо потік (натисканням кнопки Запустити) і набираємо текст уRichEdit. Текст набиратиметься безпроблем, і в цей час у компонентіTLabel працюватиме лічильник. Якби ви запустили лічильник без окремого потоку, то не змогли б набирати текст уRichEdit, тому що всі ресурси програми (основного потоку) йшли б на роботу лічильника.