Инициализация
потоков
Если вы хотите написать
код инициализации для вашего нового объекта потока, вам необходимо добавить
новый конструктор в описание вашего нового класса потока, после чего вы можете
добавлять код инициализации вместо кода реализации класса. Здесь вы можете также
указать, какой приоритет вы устанавливаете для данного потока, а также,
как должен вести себя данный поток по завершении своей работы.
Приоритеты потоков
Приоритеты потоков указывают
операционной системе, сколько процессорного времени выделяется для данного потока.
Для критических задач можно установить наивысший приоритет, для менее значимых
— более низкий приоритет.
Для установки значения
приоритета у потоков имеется свойство Priority
. Данное свойство
может принимать произвольное целое значение. Используется как бы шкала значений
приоритетов от самого низкого до наивысшего. В Linux-приложениях свойство Priority
всегда должно принимать целое числовое значение. Наибольшее числовое значение
указывает на самый высокий приоритет выполнения данного потока. Диапазон значений,
которые может принимать свойство Priority
, зависит от значения
свойства Policy
. Это свойство доступно только для Linux-приложений
и может принимать значения, перечисленные в табл. 14.1.
Таблица
14.1. Значения свойства Policy
Значение |
Тип значения |
Возможные числовые
значения для свойства |
|
|
0-99 |
|
|
0-99 |
|
|
0 |
Примечание
ЗначенияSCHED_PR
иSCHED_FIFO
могут быть установлены только в том случае, когда вы вошли в Linux под администратором (root)
Для Windows-приложений
свойство Priority
может принимать значения, перечисленные в табл.
14. 2.
Таблица
14.2. Значения свойства Priority
для Windows
Значение приоритета |
Приоритет |
Cоответствующее
числовое значение |
|
Данный поток выполняется,
когда система не занята и не выполняются никакие другие потоки Windows
не будет прекращать работу других потоков для выполнения потока, имеющего
приоритет |
-15 |
|
Низший приоритет
выполнения. Данный поток занимает минимум процессорного времени |
-2 |
|
Низкий приоритет.
Данный поток занимает немного больше процессорного времени, чем имеющий
приоритет |
-1 |
|
Нормальный приоритет.
Все потоки по умолчанию имеют приоритет |
0 |
|
Высокий приоритет.
Данный поток имеет приоритет выше нормального |
1 |
|
Высший приоритет.
Данный поток имеет приоритет выше, чем |
2 |
|
Наивысший приоритет
Поток с данным приоритетом занимает максимум процессорного времени |
15 |
Примечание
Использование высших и наивысших приоритетов может привести к замедлению работы других потоков Применение данных видов приоритетов целесообразно использовать в случае, когда возникает острая необходимость в скорейшем выполнении одного из процессов
Поведение потока
при завершении
его работы
Обычна при завершении своей
работы поток просто освобождается. Однако иногда бывает необходимо, чтобы завершение
работы и освобождение потока было согласовано с другими потоками. Например,
вы можете ожидать какое-либо значение, возвращаемое одним потоком, перед выполнением
другого потока. Для реализации этого вы не должны освобождать первый поток,
пока второй не получит значение, возвращаемое первым. Для управления завершением
работы потока существует свойство потока FreeOnTerminate
. Пo умолчанию
данное свойство установлено в true
. При этом поток освобождается
по завершении своей работы. Если же установить данное свойство в false
,
то вы можете сами завершить работу потока.
Кроме того, в Kylix имеется
возможность прекратить выполнение одного потока подачей команды о прекращении
из другого потока. Когда один поток пытается прекратить работу другого потока,
он вызывает метод Terminate
. В результате, свойство Terminate
потока будет установлено в true
, что можно проверить во время выполнения
метода Execute
(листинг 14.3).
Листинг 14.3.Проверка
прекращения работы потока
procedure TMyThread.Execute; beginwhile not Terminated do
{выполнять какие-либо задачи}; end;
Пример создания многопоточного
приложения в Kylix
Теперь настало время создания
простого многопоточного приложения.
Мы создадим приложение,
которое состоит из трех потоков (главного CLX-потока и двух потоков — потомков
класса TThread
). Для начала запустим Kylix и выберем в его главном
меню пункт File/New Application, после чего разместим на главной форме
приложения Form1 поле для редактирования Edit1, индикатор хода
выполнения работы ProgressBar1 и системный таймер Timer1. В результате
должна получиться форма, похожая на представленную на рис. 14.2.
Теперь добавим новый объект
потока через пункт главного меню Kylix File/New/Thread Object. Введем
имя для нового потомка класса TThread
, например
TMyThread1
. Kylix автоматически добавит модуль Unit2
в наше приложение.
В описание объекта TMyThread1 добавим раздел public
, в котором
опишем глобальную переменную count
.
Рис.
14.2. Форма приложения
Далее запишем в метод Execute
объекта TMyThread1
код, который должен выполняться в потоке. Пусть
это будет код, который генерирует случайные числа и присваивает их глобальной
переменной count
. Для того чтобы генераций случайных чисел была
бесконечной, зациклим ее с помощью так называемого "бесконечного цикла".
В итоге модуль Unit2
должен выглядеть так, как показано на листинге
14.4.
Листинг 14.4.Модуль
первого потока
unit Unit2; interface
uses Classes;
type TMyThread1 = class(TThread)
private
{ Private declarations } protectedprocedure Execute; override;
public
count : integer; // Добавили переменную Count end;
implementation { TMyThread1 }
procedure TMyThread1.Execute; begin
while true do
begin
count:=random (maxint);
end; end;
end.
Теперь создадим второй
объект потока, который должен заполнять индикатор хода работы ProgressBar1
.
По аналогии с первым объектом
потока при помощи главного меню Kylix создадим объект потока с именем TMyThread2
.
Во вновь добавленный модуль Unit3
включим глобальную переменную
prcount
, после чего в процедуре Execute
объекта TMyThread2
запишем код, представленный в листинге 14.5, также зациклив его.
Листинг 14.5.Модуль
второго потока
unit Unit3;
interface
uses Classes;
type
TMyThread2 = class(TThread) private{ Private declarations }
protected
procedure Execute; override;
public
prcotmt:integer; // Добавили переменную prcount end;
implementation { TMyThread2 }
procedure TMyThread2.Execute; begin
while true do begin
prcount;=prcount+1; if prcount>100 then prcount:=0; end; end;
end.
Теперь сохраним наш проект
и модули под теми именами, которые нам предложит Kylix (Project1, Unit1,
Unit2, Unit3).
Добавим в модуле
Unit1
в описание класса формы в разделе private
объекты
потоков Thread1
— потомок класса TMyThread1
и Thread2
— потомок класса TMyThread2
.
Далее дважды щелкнем на
любом свободном пространстве формы Form1
. При этом откроется "заготовка"
для метода создания формы FormCreate
. В обработчике FormCreate
напишем код, представленный в листинге 14.6.
Здесь мы создаем объект
потока с использованием конструктора Сreate
и устанавливаем приоритеты
потоков (tpLowest
и tpNormal)
.
Запишем в блоке uses
модуля Unit1
используемые модули Unit2
и Unit3
.
Нам осталось отразить результаты
вычислений, производимых потоками на форме. Для этого создадим обработчик события
OnTimer
, дважды щелкнув на объекте Timer1
. Запишем
в обработчик события OnTimer
код, представленный в листинге 14.6.
Листинг 14.6. Главный
модуль многопоточного приложения
unit Unit1; interface
uses
SysUtils, Types, Classes, Variants, QGraphics, QControls, QForms, QDialogs, QTypes, QExtCtrls, QComCtrls, QStdCtrls, unit2, unit3;
type
TForm1 = class (TForm)
Edit1: TEdit;
ProgressBar1: TProgressBar;
Timer1: TTimer;
procedure FormCreate(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
private
{ Private declarations }
thread1:tmythread1;
thread2:tmythread2;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation {$R *.xfm}
procedure TForm1.FormCreate(Sender: TObjеct); begin thread1:=tmythread1.create(false);
thread2:=tmythread2.create(false); end;
procedure TForm1.Timer1Timer(Sender: TObject); begin
edit1.Text:=inttostr(thread1.count);
progressbar1.Position:=thread2.prcount; end;
end.
Наше первое приложение,
которое использует потоки, готово. Теперь, если мы запустим приложение с помощью
главного меню Kylix: Run/Run, то сможем увидеть, как два созданных нами
потока успешно работают (рис. 14.3).
Рис.
14.3. Результат работы многопоточного приложения