Приклад створення багатопотокового додатку в Delphi
Цей розділ містить опис кроків, необхідних для створення простого, але показового прикладу багатопотокового додатку. Ми будемо намагатися обчислити число "пі" з максимальною точністю після коми. Звичайно, вбудована в Delphi константа Pi має достатню точність, правильніше сказати - максимальну, що допускається найточнішим 10-байтним форматом для дійсних чисел Extended. Так що перевершити її нам не вдасться. Але цей приклад використання потоків може послужити прологом для вирішення реальних завдань.
Перший приклад буде містити два потоки: головний (обробляє введення користувача) і обчислювальний; ми зможемо змінювати їх властивості і спостерігати за реакцією. Отже, виконайте наступну послідовність дій:
1. У середовищі Delphi відкрийте меню File і виберіть пункт NewApplication.
2. Розмістіть на формі п'ять міток і один перемикач, як показано на рис. 29.2.
Перейменуйте головну форму в fmMain.
3. Відкрийте меню File і виберіть пункт Save Project As. Збережіть модуль як uMain. а проект - як Threads 1.
Мал. 29.2. Зовнішній вигляд форми для додатка Threads'1
4. Відкрийте меню File і виберіть пункт New. Потім двічі клацніть на об'єкті типу потік (значок Thread Object). Відкриється діалогове вікно NewItems, показане на рис. 29.3.
Мал. 29.3. Діалогове вікно New Items з вибраним об'єктом типу "потік"
Мал. 29.4. Діалогове вікно New Thread Object
5. Коли з'явиться діалогове вікно для іменування об'єкту потік, введіть TPiThread і натисніть клавішу
Delphi створить новий модуль і помістить в нього шаблон для нового потоку.
6. Код, що вноситься в метод Execute. обчислює число я, використовуючи збіжність нескінченного ряду Лейбніца:
Pi = 4 - 4/3 + 4/5 - 4/7 + 4/9 -.
Зрозуміло, відображати нове значення після кожної ітерації - це те ж саме, що стріляти з гармати по горобцях. На відображення інформації система витратить в десятки разів більше часу, ніж на власне обчислення. Тому ми ввели константу updatePeriod. яка регулює періодичність відображення поточного значення.
Код методу Execute показаний нижче:
// Краще використовувати непарне число для того, щоб уникнути ефекту // мерехтіння UpdatePeriod = 1000001;
procedure TPiThread.Execute; var sign. Integer;
PiValue, PrevValue. Extended; i. Int64;
PiValue: = PiValue + sign * 4 / (2 * i + l); sign: = -sign;
if i mod UpdatePeriod = 0 then
GlobalPi: = PiValue; GlobalCounter: = i; Synchronize (fmMain.UpdatePi);
until Terminated or (Abs (PiValue - PrevValue)<1E-19); end;
7. Відкрийте меню File і виберіть пункт Save As. Збережіть модуль з потоком як uPiThread .pas.
8. Відредагуйте головний файл модуля uMain.pas і додайте модуль uPiThread до списку використовуваних модулів в секції інтерфейсу. Він повинен виглядати так:
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, StdCtrls, uPiThread;
9. У секції public форми TfmMain додайте посилання на створювану нитка: PiThread. TPiThread;
10. Додайте в модуль uMain дві глобальні змінні
і метод UpdatePi:
if Islconic (Application.Handle) then
LaValue.Caption: = FloatToStrF (GlobalPi, ffFixed, 18, 18);
lalterNum.Caption: = IntToStr (GlobalCounter) + 'iterations';
Цей метод, якщо ви звернули увагу, викликається з потоку за допомогою процедури Synchronize. Він відображає поточне значення наближення до числа "пі" та кількість ітерацій.
У разі, якщо головне вікно програми згорнуто, відображення не виробляється; так що після його розгортання вам, можливо, доведеться почекати деякий час для оновлення.
11. Виконайте подвійне клацання на вільному місці робочої області форми, при цьому створиться шаблон методу FormCreate. Тут ми відобразимо значення системної константи р ±:
procedure TfmMain.FormCreate (Sender: TObject);
laBuiltln.Caption: = FloatToStrF (Pi, ffFixed, 18, 18); end;
12. Виберіть на формі перемикач (його назва cbcalcuiate) і призначте події Onclick код, який створює і знищує обчислювальний потік залежно від стану перемикача:
procedure TfmMain.cbCalculateClick (Sender: TObject);
begin if cbCalculate.Checked then
PiThread.Resume; end else begin
if Assigned (PiThread) then PiThread.Terminate;
Таким чином, багатопоточний додаток готове до запуску. Якщо все пройде нормально, ви побачите картинку, подібну до тієї, яка наведена на рис. 29.5.
Мал. 29.5. Що виконується додаток Threads1
Цей простий приклад - перший крок в засвоєнні того, як від базового класу rrhread можна породжувати власні класи. Через свою простоту він не позбавлений недоліків; більш того - якби обчислювальних ниток було не одна, а більше, деякі прийоми були б навіть помилковими. Але - про це нижче.