Инициализация потоков

Если вы хотите написать код инициализации для вашего нового объекта потока, вам необходимо добавить новый конструктор в описание вашего нового класса потока, после чего вы можете добавлять код инициализации вместо кода реализации класса. Здесь вы можете также указать, какой приоритет вы устанавливаете для данного потока, а также, как должен вести себя данный поток по завершении своей работы.

Приоритеты потоков

Приоритеты потоков указывают операционной системе, сколько процессорного времени выделяется для данного потока. Для критических задач можно установить наивысший приоритет, для менее значимых — более низкий приоритет.

Для установки значения приоритета у потоков имеется свойство Priority. Данное свойство может принимать произвольное целое значение. Используется как бы шкала значений приоритетов от самого низкого до наивысшего. В Linux-приложениях свойство Priority всегда должно принимать целое числовое значение. Наибольшее числовое значение указывает на самый высокий приоритет выполнения данного потока. Диапазон значений, которые может принимать свойство Priority, зависит от значения свойства Policy. Это свойство доступно только для Linux-приложений и может принимать значения, перечисленные в табл. 14.1.

Таблица 14.1. Значения свойства Policy

Значение

Тип значения

Возможные числовые значения для свойства Priority

SCHED_RR

Real Time

0-99

SCHED_FIFO

Real Time

0-99

SCHED_ОTHER

Regular

0

Примечание
Значения SCHED_PR и SCHED_FIFO могут быть установлены только в том случае, когда вы вошли в Linux под администратором (root)

Для Windows-приложений свойство Priority может принимать значения, перечисленные в табл. 14. 2.

Таблица 14.2. Значения свойства Priority для Windows

Значение приоритета

Приоритет

Cоответствующее числовое значение

Tpldle

Данный поток выполняется, когда система не занята и не выполняются никакие другие потоки Windows не будет прекращать работу других потоков для выполнения потока, имеющего приоритет tpldle

-15

TpLowest

Низший приоритет выполнения. Данный поток занимает минимум процессорного времени

-2

TpLower

Низкий приоритет. Данный поток занимает немного больше процессорного времени, чем имеющий приоритет tpLowest

-1

TpNormal

Нормальный приоритет. Все потоки по умолчанию имеют приоритет tpNormal

0

TpHigher

Высокий приоритет. Данный поток имеет приоритет выше нормального

1

TpHighest

Высший приоритет. Данный поток имеет приоритет выше, чем tpHigher

2

TpTimeCntical

Наивысший приоритет Поток с данным приоритетом занимает максимум процессорного времени

15

Примечание

Использование высших и наивысших приоритетов может привести к замедлению работы других потоков Применение данных видов приоритетов целесообразно использовать в случае, когда возникает острая необходимость в скорейшем выполнении одного из процессов

Поведение потока
при завершении его работы

Обычна при завершении своей работы поток просто освобождается. Однако иногда бывает необходимо, чтобы завершение работы и освобождение потока было согласовано с другими потоками. Например, вы можете ожидать какое-либо значение, возвращаемое одним потоком, перед выполнением другого потока. Для реализации этого вы не должны освобождать первый поток, пока второй не получит значение, возвращаемое первым. Для управления завершением работы потока существует свойство потока FreeOnTerminate. Пo умолчанию данное свойство установлено в true. При этом поток освобождается по завершении своей работы. Если же установить данное свойство в false, то вы можете сами завершить работу потока.

Кроме того, в Kylix имеется возможность прекратить выполнение одного потока подачей команды о прекращении из другого потока. Когда один поток пытается прекратить работу другого потока, он вызывает метод Terminate. В результате, свойство Terminate потока будет установлено в true, что можно проверить во время выполнения метода Execute (листинг 14.3).

Листинг 14.3.Проверка прекращения работы потока

procedure TMyThread.Execute; 
begin
while 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-02-1.jpg

Рис. 14.2. Форма приложения

Далее запишем в метод Execute объекта TMyThread1 код, который должен выполняться в потоке. Пусть это будет код, который генерирует случайные числа и присваивает их глобальной переменной count. Для того чтобы генераций случайных чисел была бесконечной, зациклим ее с помощью так называемого "бесконечного цикла". В итоге модуль Unit2 должен выглядеть так, как показано на листинге 14.4.

Листинг 14.4.Модуль первого потока

unit Unit2; interface
uses Classes;
type TMyThread1 = class(TThread)
private
{ Private declarations } protected
procedure 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-02-2.jpg

Рис. 14.3. Результат работы многопоточного приложения

Hosted by uCoz