Мова програмування Delphi.
потоки:
Сьогодні нам належить познайомитися з потоками. Ця штука дуже цікава і нещадно потрібна. Все програмування звуку буде написано з використанням потоків, так що вникай де суть.
Уяви, що ти хочеш вставити в свою прогу перевірку орфографії. Якщо ти після кожної натиснутоюклавіші будеш перевіряти правильність слів, то твоя прога буде божевільно гальмувати. А як же це робить MS Word? Дуже просто, після запуску проги запускається потік, який у фоновому режимі проводить перевірку орфографії. Ти спокійно набираєш текст і навіть не відчуваєш (майже) як паралельний процес у вільний час проводить складні перевірки твоїх каракуль.
Будь-яка програма містить хоча б один потік (головний), в якому вона виконується. Крім цього, вона може породжувати будь-яку кількість додаткових потоків, які будуть виконуватися у фоновому режимі. У додаткових потоків пріоритет виставляється такий же як і у головного потоку програми, але ти його можеш збільшити або зменшити. Чим вище пріоритет потоку, тим більше на нього відводиться процесорного часу.
Так що тут розпинатися, давай програмувати. З усім розберемося в процесі.
Створи новий проект. Постав на форму ТRichEdit з палітри Win32 і один TLabel. Це ми створили форму, а тепер створимо потік.
Вибери File-> New (рисунок 1). Знаходиш там Thread Object, вирізняєш і щёлкаешь "ОК". З'являється віконце, як на малюнку 2. Вводимо ім'я потоку (я ввів TCountObj). Зберігаємо весь проект. Головну форму під ім'ям main (як завжди), а потік під ім'ям MyThread.
Після цього Delphi створить ось такий код:
unit MyThread;interface uses Classes;type TCountObj = class (TThread) private {Private declarations} protected procedure Execute;override;end;implementation {Important: Methods and properties of objects in VCL can
only be used in a method called using Synchronize , for example, Synchronize (UpdateCaption); and UpdateCaption could look like, procedure TCountObj.UpdateCaption; begin Form1.Caption: = 'Updated in a thread'; end; } {TCountObj} procedure TCountObj.Execute; begin {Place thread code here} end; end.
Це новий потік. У об'єкта є тільки одна функція Execute. У цій функції ми і будемо писати код потоку. Напишемо ось що:
procedure TCountObj.Execute;begin index: = 1;// Запускаємо нескінченний лічильник while index> 0 do begin Synchronize (UpdateLabel);Inc (index);if index> 100000 then index: = 0;// Якщо потік зупинений, то вийти.if terminated then exit;end;end;index я оголосив як integer в розділі private потоку. Там же я оголосив процедуру UpdateLabel. Ця процедура виглядає так:
procedure TCountObj.UpdateLabel;begin Form1.Label1.Caption: = IntToStr (Index);end;
І останнє, що я зробив - підключив головну форму в розділ uses, тому що я звертаюся до неї в коді вище (Form1.Label1.Caption).
Тепер про магічну функції Synchronize. Як параметр їй передається процедура UpdateLabel, яка виробляє висновок в головну форму. Для чого потрібно вставляти висновок на екран в Synchronize? Бібліотека VCL має один косяк - вона не захищена від потоків. Якщо головна форма і потік спробують одночасно вивести що-небудь в одну і ту ж область екрану або компонент, то програма впаде як ефелева вежа. Тому весь висновок на форму потрібно виділяти в окрему процедуру і викликати цю процедуру за допомогою Synchronize.
Що відбувається під час виклику Synchronize? У цей момент потік зупиняється і управління передається головному потоку, який і зробить оновлення.
Наш потік готовий. Повертаємося до головної формі. Я її зробив, як на рис 3. В розділ uses (найперший, який йде після interface) я додав свій потік MyThread.
У розділі private я оголосив змінну co типу TCountObj (об'єкт мого потоку).
При натисканні кнопки "Запустити" я написав такий код:
procedure TForm1.Button1Click (Sender: TObject);begin co: = TCountObj.Create (true);co.Resume;co.Priority: = tpLower;end;У першому рядку я створюю потік co. Як параметр може бути true або false. Якщо false, то потік відразу починає виконання, інакше потік створюється, але не запускається. Для запуску потрібно використовувати Resume, що я роблю в другому рядку.
У третьому рядку я встановлюю пріоритет потоку поменше, щоб він не заважав роботі основного потоку і виконувався в тлі. Якщо встановити пріоритет вище, то основний потік почне пригальмовувати, тому що у них будуть однакові пріоритети.
За кнопці "Зупинити" я написав:
procedure TForm1.Button1Click (Sender: TObject);begin co.Terminate;co.Free;end;
У першому рядку я зупиняю виконання потоку, а в другій знищую його.
Спробуй запустити прогу, запустити потік (натисканням кнопки "Запустити") і понабирали текст в RichEdit. Текст буде набіратся без проблем, і в цей час в ТLabel буде працювати лічильник. Якби ти запустив лічильник без окремого потоку, то ти б не зміг набирати текст в RichEdit, тому що всі ресурси програми (основного потоку) йшли б на роботу лічильника.
Отже, наш перший потік готовий. При програмуванні звуку ми напишемо більш корисні приклади з потоками. А зараз ще кілька корисних фішок:
- Suspend - призупиняє потік. Для виклику просто напиши co.Suspend. Щоб відновити роботу з цієї ж точки потрібно викликати Resume.
- Priority- встановлює пріоритет потоку. Наприклад Priority: = tpIdle;
- tpIdle - потік буде працювати тільки коли процесор ледарює.
- tpLowest - найслабший пріоритет
- tpLower - слабкий пріоритет
- tpNormal - нормальний
- tpHigher - високий
- tpHighest - найвищий
- tpTimeCritical - критичний (не раджу використовувати, тому що може грохнути систему).
- Suspended - якщо цей параметр true, то потік знаходиться в паузі.
- Terminated - якщо true, то потік повинен бути зупинений.
От і все. З потоками закінчено.
Вихідні тексти прикладу забирай тут
А як же це робить MS Word?Для чого потрібно вставляти висновок на екран в Synchronize?
Що відбувається під час виклику Synchronize?