Современные операционные системы Windows 32 обеспечивают не только многозадачность, т. е. возможность параллельной работы нескольких программ, но и многопоточность, когда в рамках одной программы организуется несколько параллельно выполняемых фрагментов (потоков), каждый из которых конкурирует с другими потоками за наиболее важный ресурс - время центрального процессора. В многопоточном режиме время ЦП выделяется для каждого процесса небольшими порциями (квантами), по истечении этого времени управление передается другому потоку и т. д. до тех пор, пока потоки не закончат свою работу. В любой работающей программе организуется как минимум один поток для команд программы. С помощью объектов класса TThread программа может создать дополнительные потоки для проведения некоторой фоновой работы (например, текстовый процессор Word создает дополнительные потоки для проверки правильности орфографии, разбивки на страницы, печати документа и т. п.).
Для создания дополнительного потока в программах Delphi предназначен специальный модуль потока в репозитории он обозначен пиктограммой Thread Obiecll). При выборе этого модуля Delphi запрашивает имя класса, который будет дочерним для основополагающего класса TThread. Необходимость наследования связана с тем, что класс TThread содержит абстрактный метод Execute, который, собственно, и должен исполняться в рамках нового потока и который, следовательно, обязан перекрываться в потомках.
После указания имени дочернего класса Delphi раскрывает дополнительный модуль с обширным комментарием и заготовкой для дочернего класса.
Например (с соответствующим переводом):
unit Unit1;
interfaceuses
Classes;
type
MyThread = class(TThread)
private{ Private declarations }protectedprocedure Execute; override;
end;
implementation{ Важно: Методы и свойства объектов из библиотеки визуальных компонентов
могут использоваться только в рамках вызова метода Synchronize, например:
Synchronize(UpdateCaption);
где метод UpdateCaption должен быть подобен такому
procedure MyThread.UpdateCaption;
begin
Formi.Caption := "Новый текст метки";
end; }
(MyThread}
procedure MyThread.Execute;
begin{ Пожалуйста, поместите код потока в этом месте }end;
end.
Программирование потока ничем не отличается от программирования обычной программы за одним важным исключением: поток не должен использовать методы и свойства визуальных компонен тов, которые приводят к изменению внешнего вида программа Точнее, он может это делать только при обращении к специальному методу synchronize, с помощью которого осуществляется синхронизация исполнения главного потока программы с дополнительным потоком.
Для иллюстрации приемов работы с потоком создадим программу, которая будет непрерывно обновлять содержимое многострочного редактора и при этом осуществлять математические вычисления.
Для ее создания сначала на пустую форму поместите панель TPpanel, очистите ее свойство caption и поместите в Align значение аlRight - эта панель предназначена для размещения редактора TSpinEdit, кнопки TButton и индикатора TGauge и всегда должна располагаться в правой части окна программы. Поместите на панель перечисленные компоненты так, как это показано на рисунке (компоненты TSpinEdit и TGuage находятся на странице samples палитры компонентов).
Установите в свойство SpinEditl.Value 3начение 2, присвойте свойству Gaugel. Kind значение gkPie, Gaugel. BorderStyle-bsNone и Button1.Caption — "Квадрат".
На свободное место формы положите компонент TMemo и установите для него в свойство Align значение alСlient, а свойство Name- "mmOutput".
Теперь создадим обработчик события Button1.Click: при нажатии на кнопку вначале содержимое редактора SpinEdit1 возводится в квадрат до тех пор, пока отображаемое в нем значение не слишком большим (больше 10 +1233 ). В этот момент надпись на кнопке меняется на “корень”, а нажатие на нее вычисляет корень квадратный ИЗ величины SpinEdit1.
Дважды щелкните по кнопке Button1и напишите такой код:
procedure TForm1.Button1Click(Sender: TObject);
beginif Tag = 0 thenbegin
SpinEditl.Text := Float - ToStr(sqr(StrToPloat(SpinEditl.Text)));
if StrToFloat(SpinEditl.Text) > 1 el233 thenbegin
Tag := 1;
Buttoni.Caption := "Корень"
endendelsebegin
SpinEditl.Text := FloatToStr(sqrt(StrToFloat(SpinEditl.Text)));
if StrToFloat(SpinEditl.Text) < 2 thenbegin
SpinEditl.Value := 2;
Tag := 0;
Button1.Caption := "Квадрат"
endendend;
Таким образом, главный код программы связан с извлечением корня или возведением в квадрат величины, записанной в редакторе SpinEditl.
Теперь создадим модуль потока, в методе Execute которого будем непрерывно формировать по 100 строк в редакторе mmOutput и показывать процент заполнения редактора с помощью индикатора Gaugel.
Выберите пиктограмму модуля потока в окне репозитория Delphi и дайте наследнику класса Thread имя ThreadDemo. Окончательный текст модуля потока представлен ниже.
unit Unit2;
interfaceuses
Classes;
type
ThreadDemo = class(TThread)
private{ Private declarations }protected
S: string;
N: Integer;
procedure UpdateMemo;
procedure UpdateGauge;
procedure Execute; override;
end;
var
TDemo: ThreadDemo;
implementationuses Uniti, SysUtils;
{ Important: Methods and properties of objects in VCL can only re used.
in a method called using Synchronize, for example,
Synchronize(UpdateCaption);
and UpdateCaption could look like,
procedure ThreadDemo.UpdateCaption;
begin
Formi.Caption := "Updated in a thread";
end;
ThreadDemo}procedure ThreadDemo.Execute;
var
j, k: Integer;
beginrepeat
S := "";
Synchronize(UpdateMemo);
for k := 0 to 99 dobegin N := k;
S: = " ";
for j := 1 to 20 do
S := S + FormatFloat("00", k), Synchronize(UpdateMemo);
Synchronize(UpdateGauge)
end;
until False
end;
procedure ThreadDemo.UpdateMemo;
beginwith .Form1.mmOutput.Lines doif S = " " then
Clear else
Add(S)
end;
procedure ThreadDemo.UpdateGauge;
begin
Form1.Gaugel.Progress := N
end;
end.
Если вы запустите таким способом подготовленную программу, то ничего не произойдет - ведь мы еще не запустили поток. Чтобы сделать это, добавьте в модуле Unit1 главной формы ссылку uses Unit1, раскройте в окне Инспектора объектов список компонентов, выберите компонент Form1 и на его странице Event дважды щелкните по свойству onActivate, чтобы создать такой обработчик этого события:
procedure TForm1.FormActivate(Sender: TObject);
begin
TDemo := ThreadDemo.Create(False),
end;
Вот так просто запускается дополнительный поток - мы инициируем объект TDemo, передавая в его Консруктор ThreadDemo.Create
единственный параметр False (этот параметр показывает, должен ли вновь созданный поток “спать” - True или он обязан немедленно начать работу - False). Программа в любой момент может приостановить работу потока, присвоив его свойству suspended значение True, и продолжить его выполнение, присвоив этому свойству значение False. Обратите внимание - метод Execute потока вынесен в секцию protected и поэтому недоступен из основного модуля. Выполнение этого метода начинается автоматически, как только свойство suspended примет значение False.
Для обращения к свойствам и методам визуальных компонентов формы Form1 предназначен специальный метод потока Synchronize. Единственным параметром обращения к этому методу должно быть имя любой потоковой процедуры без параметров. Внутри такой процедуры разрешается обращаться к методам и свойствам визуальных компонентов. В нашем потоке две такие процедуры - UрdateMemo и updateGuage. В первой строка s добавляется к содержимому редактора mmoutput, во втором - глобальная переменная n присваивается свойству progress индикатора Gauge1. Поскольку эти процедуры не могут иметь параметров, для управления их работой приходится использовать глобальные переменные S и N.
Если Вас заинтересовала или понравилась информация по разработке на Delph - "Особенности разработки потоков", Вы можете поставить закладку в социальной сети или в своём блоге на данную страницу: Так же Вы можете задать вопрос по работе этого модуля или примера через форму обратной связи, в сообщение обязательно указывайте название или ссылку на статью!