Можно много
и очень долго говорить о многозадачности и многопоточности, о це-лесообразности
использования потоков и т.д. и т.п. Но я не буду "лить воду".
Скажу лишь, что прежде чем создавать отдельный поток, сначала подумайте,
нужно ли это в Вашей программе. Ведь для создания даже маленького
потока необходимы ресур-сы системы. Целесообразно в поток помещать
процедуры, требующие достаточно большого времени выполнения, например
поиск файлов, загрузка файлов из Интер-нета, работа с сетевой базой
данных, создание сложных визуальных эффектов и т.д.
И так…
Класс TThread.
Для начала немного теории, которая понадобится нам для создания
первого примера приложения с потоком.
Самое первое и самое главное: TThread - АБСТРАКТНЫЙ класс!!!
Т.е. НИКОГДА не используйте его напрямую, а то потом долго не разберетесь,
откуда появляется ошибка! Для использования класса TThread
необходимо создать класс-потомок:
type
TMyThread = Class (TThread);
…
end;
Вот некоторые методы класса TThread, которые нам понадобятся
для начала:
constructor Create(CreateSuspended: Boolean);
procedure Resume;
procedure Suspend;
function Terminate: Integer ;
procedure Execute; virtual; abstract;
procedure Synchronize (Method: TThreadMethod);
Параметр конструктора Create означает, как будет запущен поток после
создания: немедленно (False) или попозже (True).
Если Вы создали поток с параметром True, то для его запуска необходимо
будет вызвать метод Resume.
Suspend - приостанавливает выполнение потока;
Resume - продолжает выполнение потока;
Terminate - пытается завершить поток путем установки
свойства Terminated в True. Для прекращения выполнения потока во
время работы, необходимо периодически проверять свойство Terminated
в пределах метода Execute (см. ниже) и во всех мето-дах,
которые Execute вызывает, и выходить, если Terminated=True.
Execute - содержит основной код потока, т.е. те действия,
которые Вы решили по-местить в поток. Если Вы обратили внимание,
этот метод абстрактный, т.е. его надо переопределять в пределах
Вашего класса-потомка TThread.
Synchronize - используется для предотвращения одновременного
доступа разных потоков к одному элементу VCL. Дело в том, что код
VCL выполняется в главном потоке программы, так что поток должен
синхронизироваться, если он использует код VCL. Параметр метода
- это метод без параметров, который обычно принадле-жит Вашему потоковому
классу.
И еще одно: не желательно создавать элементы VCL в потоке, т.к.
сообщения системы не будут посылаться манипуляторам окон, созданных
в потоке. Правда есть некоторые элементы VCL, которые являются потокозащищенными.
Это TCanvas, который имеет методы Lock и UnLock,
которые запрещают и разрешают (соответст-венно) доступ к канве для
других потоков. Кроме того, класс TThreadList позволяет
нескольким потокам работать с TList.
Ну вот, немного теории уже есть, пора и к практике переходить :-)
Давайте для примера создадим простую программу, которая будет что-то,
например - крестики, выводить на канву формы в единственном потоке.
Для этого нам понадобится создать новый проект, на форму которого
нужно будет поместить всего две кнопки - Botton1 и
Button2, а в секцию private описания формы добавим
PT : TMyThread;
Далее создадим свой собственный потоковый класс (перед описанием
класса фор-мы!):
type
TmyThread = class (TThread)
private
X, Y, Color : Integer;
protected
procedure Execute; override;
procedure Paint;
end;
Далее, естественно, опишем методы Execute и Paint:
procedure TMyThread.Execute;
begin
Randomize;
X:=0;Y:=0;
repeat
X:=Random(Form1.Width);
Y:=Random(Form1.Height);
Color:=Random($FFFFFFFF);
Synchronize (Paint);
until Terminated;
end;
procedure TMyThread.Paint;
begin
with Form1.Canvas do begin
Pixels[X,Y-1]:=Color;
Pixels[X+1,Y]:=Color;
Pixels[X-1,Y]:=Color;
Pixels[X,Y+1]:=Color;
Pixels[X,Y]:=Color;
end;
end;
И не забудем создать обработчики для кнопок:
procedure TForm1.Button1Click(Sender: TObject);
begin
Button1.Enabled:=False;
Button2.Enabled:=True;
PT:=TMyThread.Create(False);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
Button1.Enabled:=True;
Button2.Enabled:=False;
PT.Free;
end;
Вот и все. Запускаем, должно получиться :-)
PS: Продолжение следует в недалеком будущем ;-)
|