Вне зависимости от того, хотим мы этого или нет, но прогресс движется
дальше, появляются все новые технологии, новые процессоры, новые "высоты"
производительности. В связи с этим, все чаще программистам приходится
разрабатывать программы, которые используют сложные операции, в которых
важна скорость и которые выполнялись бы одновременно с другими. Этому
вопросу как раз и посвящена данная статья - создание многопоточных
приложений (со множеством дочерних процессов, которые выполняются
одновременно).
Зачем нужен Thread
Итак, зачем же нужен класс Thread и его потомки? Во-первых, этот
объект позволяет создавать как бы несколько программ в одной
(несколько процессов, или, потоков). Во-вторых, эти процессы
могут выполняться как по очереди, так и одновременно (как
запрограммирует разработчик). В-третьих, из этих процессов
можно легко получить доступ ко всем глобальным данным программы,
т.к. класс процесса является, по сути, просто частью программы -
обычным юнитом (unit). В-четвертых, можно создать своих собственных
потомков TThread и запустить сразу несколько экземпляров одного и
того же созданного класса. В-пятых, каждым процессом очень легко
управлять - запускать, завершать, приостанавливать, прерывать,
устанавливать приоритетность, и т.д.
Краткое описание класса TThread
Итак, рассмотрим некоторые свойства, методы и события класса TThread.
Свойства
Методы
События
FreeOnTerminate - освобождать ли
память, выделенную под экземпляр класса процесса, когда
этот процесс завершается. Если True - при завершении
процесса (или при вызове метода Terminate) экземпляр
класса автоматически освобождается (аналогично вызову метода
Free).
Тип: Boolean; Handle (ThreadID) - дескриптор процесса.
Эта величина может быть использована для управления процессом
через функции WinAPI.
Тип: THandle; ReturnValue - возвращаемое
значение при завершении процесса.
Тип: Integer; Priority - приоритет процесса.
Возможные значения этого свойства мы разберем немного позже.
Тип: TThreadPriority; Suspended - показывает, в
каком состоянии находится процесс: True - приостановлен,
False - в нормальном.
Тип: Boolean; Terminated - показывает,
завершен ли процесс. True - завершен, False - нет.
Тип: Boolean;
Create(CreateSuspended: Boolean) -
создает экземпляр класса. Параметр CreateSuspended
указывает на то, нужно ли создавать приостановленную задачу
(True), или запускать ее сразу (False); Suspend - приостанавливает
выполнение процесса; Resume - продолжает
выполнение процесса после Suspend; Terminate - полностью
прекращает выполнение процесса; WaitFor - ждет завершения
процесса, возвращая затем код его завершения (ReturnValue); Synchronize(Method: TThreadMethod)
- синхронизирует выполнение метода процесса, позволяя ему
работать параллельно с другими процессами.
OnTerminate - возникает, когда
процесс находится в стадии завершения.
Приоритет процесса
Итак, что же такое приоритет? Приоритет - это величина, определяющая,
насколько данный процесс должен выполнятся быстрее по сравнению с другими.
Т.е., другими словами, чем выше приоритет процесса, тем больше времени
он отбирает у системы и других, параллельно работающих процессов. Далее
разберем возможные значения свойства Priority класса TThread в порядке
возрастания приоритета:
tpIdle - процесс выполняется только тогда, когда система
не занята и больше нет работающих в данных момент процессов;
tpLowest - на два пункта ниже нормального;
tpLower - на один пункт ниже нормального;
tpNormal - нормальный. Такой приоритет у большинства задач;
tpHigher - на один пункт выше нормального;
tpHighest - на два пункта выше нормального;
tpTimeCritical - самый высокий приоритет - занимает все
время процессора и системы. Это приоритет для систем реального времени,
для которых важна каждая секунда и даже малейшая задержка может привести
к сбою. Будьте осторожны с этим приоритетом!
Практика и примеры
Приведем небольшой пример того, как можно создать отдельный процесс:
Пример 1. "Шаблон" для создания Thread-ов.
{Определение класса TMyThread}
type
TMyThread = class(TThread)
private
{ Private declarations }
protected
procedure DoWork;
procedure Execute; override;
end;
implementation
procedure TMyThread.Execute;
begin
{Если Вы хотите, чтобы процедура DoWork выполнялась лишь один раз - удалите цикл while}
while not Terminated do
Synchronize(DoWork);
end;
procedure TMyThread.DoWork;
begin
{Здесь можно уже выполнять те задачи, которые должны быть исполнены процессом}
end;
А теперь - замечательный пример для изучения Thread! В нижеследующем примере
приложение создает два параллельно работающих процесса. Один Thread
пытается установить флажок CheckBox1 в положение "включено" (Checked := True),
а другой, передергивая первого - в "выключено".
Пример 2. "Поединок" Thread-ов :-).
{В форму Form1 нужно поместить TCheckBox - CheckBox1
и одну кнопку TButton - Button1}{Определение классов двух Thread-ов}
type
TMyThread1 = class(TThread)
private
{ Private declarations }
protected
procedure DoWork;
procedure Execute; override;
end;
TMyThread2 = class(TThread)
private
{ Private declarations }
protected
procedure DoWork;
procedure Execute; override;
end;
var Form1: TForm1;
T1 : TMyThread1;
T2 : TMyThread2;
implementation
procedure TMyThread1.Execute;
begin
{Пока процесс не прервали, выполняем DoWork}
while not Terminated do
Synchronize(DoWork);
end;
procedure TMyThread2.Execute;
begin
{Пока процесс не прервали, выполняем DoWork}
while not Terminated do
Synchronize(DoWork);
end;
procedure TMyThread1.DoWork;
begin
{Пытаемся победить второй процесс :-)}
Form1.CheckBox1.Checked := True;
end;
procedure TMyThread2.DoWork;
begin
{Пытаемся победить первый процесс :-)}
Form1.CheckBox1.Checked := False;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
{Если кнопка называется Stop...}
if Button1.Caption = 'Stop' then begin
{Прерываем оба процесса}
T1.Terminate;
T2.Terminate;
{Изменяем название кнопки}
Button1.Caption := 'Start';
{Выходим из процедуры}
Exit;
end;
{Создаем и сразу запускаем два процесса}
T1 := TMyThread1.Create(False);
T2 := TMyThread2.Create(False);
{Здесь можно поэкспериментировать с приоритетами:
T1.Priority := tpLowest;
T2.Priority := tpHighest;
}{Переименовываем кнопку}
Button1.Caption := 'Stop';
end;
P.S. Отличный пример работы с TThread можно найти в подкаталоге
Demos\Threads каталога, куда Вы установили Borland Delphi.
Эпилог
В этой статье отображены основные стороны работы с процессами (потоками)
Thread в Borland Delphi. Если у Вас есть вопросы - скидывайте их мне на E-mail:
snick@mailru.com, а еще лучше - пишите
в конференции этого сайта (Delphi. Общие вопросы), чтобы и другие пользователи
смогли увидеть Ваш вопрос и попытаться на него ответить!
Внимание! Запрещается перепечатка данной
статьи или ее части без согласования с автором. Если вы хотите разместить эту
статью на своем сайте или издать в печатном виде, свяжитесь с автором. Автор статьи:Карих Николай