Введение
Вне зависимости от того, хотим мы этого или нет, но прогресс движется дальше,
появляются все новые технологии, новые процессоры, новые "высоты"
производительности. В связи с этим, все чаще программистам приходится
разрабатывать программы, которые используют сложные операции, в которых важна
скорость и которые выполнялись бы одновременно с другими. Этому вопросу как раз
и посвящена данная статья - создание многопоточных приложений (со множеством
дочерних процессов, которые выполняются одновременно).
Зачем нужен 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.
{Определение класса 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.
{В форму 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. Общие вопросы), чтобы и другие пользователи
смогли увидеть Ваш вопрос и попытаться на него ответить!
Автор: Карих Николай
|