П р и м е р 3. Создается многопоточное приложение, в котором демонстрируется образование и приостановка трех потоков, изменение их приоритетов и уничтожение (освобождение ресурсов). Пользовательский интерфейс приложения имеет следующий примерный вид (см. рис. 4)
Рис.4
Назначение элементов интерфейса:
[1] – в программе создается три потока, каждый из которых перемещает изображение (например, автомобиль) по форме.
[2] – изменение приоритета позволяет эффективно распределять процессорное время между потоками в системе.
[3] – поток можно приостановить (suspend), если, к примеру, он ожидает данные, и тогда время процессора для этого потока планироваться (выделяться) не будет, что позволит эффективнее использовать ресурсы.
[4] – приостановленный поток можно снова запустить (resume), при этом поток опять становиться планируемым и ему выделяется процессорное время.
Для создания приложения выполните следующие действия:
1. Открыте новый проект командой главного меню File|New Application и введите текст заголовка: «Пример 3. Многопоточное приложение с тремя потоками».
2. Создайте главную форму по рис. 4, поместив на нее со страницы Standard следующие компоненты:
• три компоненты типа PaintBox, разместив их в верхней части формы таким образом: первый в самом верху, верх и левый край второго совпадает с низом и левым краем первого, верх и левый край третьего совпадает с низом и левым краем второго. Все три компоненты будут использованы для отображения графических изображений;
• ниже поместите три компонента TrackBar которые будут использоваться для изменения приоритета потоков;
• под каждой компонентой TrackBar поместите по кнопке с заголовком Start. Эти кнопки будут запускать потоки;
• под этими кнопками поместите еще три кнопки с заголовками Stop, которые будут приостанавливать потоки. (Можно использовать только три кнопки вместо шести, динамически меняя их заголовки и действия, которые с ними связаны).
3. Добавите модуль командой File|New Other|Thread Object.
4. Введите имя Вашего класса (рекомендуется, чтобы первая буква была "T", например TMoveThread). В модуле добавьте в секцию uses модули Graphics, ExtCtrls.
5. В секцию type добавить следующие переменные:
private
FBox: TPaintBox; // Где воспроизводится картинка
b0,b1: tbitmap; // Сами картинки
i:integer; // Для определения координат картинки
procedure DoVisualSwap; // Одна процедура двигает вправо,
procedure DoVisual; // Другая влево
protected
procedure Execute; override;
public
constructor Create(a,b: TBitmap; c:TPaintBox);
destructor Destroy; override;
end;
6. В секции implementation создайте конструктор и деструктор:
constructor TMoveThread.Create(a,b:tbitmap; c:TPaintBox);
begin
b0:=a;b1:=b;Fbox:=c;i:=0;
inherited Create(False);
end;
destructor TMoveThread.Destroy;
begin
b0.free;
b1.free;
inherited Destroy;
end;
7. Введите тексты процедур модуля, выполняющих прорисовку объекта:
procedure TMoveThread.DoVisualSwap; { Двигает картинку вправо }
begin
with FBox do
begin
canvas.Draw(i,0,b0);
inc(i);
end;
end;
procedure TMoveThread.DoVisual; { Двигает картинку влево }
begin
with FBox do
begin
canvas.Draw(i,0,b1);
dec(i);
end;
end;
8. Введите текст главной процедуры модуля:
procedure TMoveThread.Execute; {В зависимости от координат, картинка двигается
влево или вправо }
begin
while true do
begin
while i<=(fbox.Width+b0.Width) do Synchronize(DoVisualSwap);
while i>=(0-b0.Width) do Synchronize(DoVisual);
end;
end;
9. В секцию interface uses добавьте модуль Movethds.
10. В секции interface public объявите три объекта:
Thread1,
Thread2,
Thread3:TMoveThread;
11. Создайте потоки для анимации картинок в обработчике события FormCreate:
taxi00:=tbitmap.Create; // Создается объект BitMap
taxi00.LoadFromFile('taxi00.bmp'); //В него загружается изображение
taxi01:=tbitmap.Create;
taxi01.LoadFromFile('taxi01.bmp');
thread1:= TMoveThread.Create(taxi00,taxi01,PaintBox1); //Создается поток
Thread1.Priority:=tpLowest; / Устанавливается небольшой приоритет у потока; это необходимо для того, чтобы поток был управляемым и не забирал все ресурсы.
12. Аналогично создайте еще два потока для PaintBox2, PaintBox3, используя последние две строчки примера в п.11 и изменяя имена потоков.
13. Приостановка потоков. Для того чтобы определить, приостановлен ли поток используется метод Suspended (приостановить). Для приостановки потока используется метод Suspend. Таким образом, сначала проверяется, приостановлен ли поток, а затем, если надо, он приостанавливается. Например, для первого потока это можно сделать следующим образом:
if Thread1.Suspended=false then Thread1.Suspend.
Эти строки кода необходимо написать в обработчике события OnClick для кнопок Stop всех потоков.
14. Возобновление потоков. Для этого необходимо проверить приостановлен ли поток, а затем возобновить его с помощью метода Resume, например:
if Thread1.Suspended=true then Thread1.Resume.
Эти строки кода также необходимо написать в обработчике события OnClick для кнопок Start всех потоков.
15. Изменение приоритетов потоков. Изменить приоритет потоков можно используя свойство Priority. Для определения приоритетов потоков используются компоненты TrackBar, а для изменения - событие OnChange этих компонентов. В данном случае используется одна процедура вместо трех и ее текст приводится целиком:
procedure TForm1.TrackBar1Change(Sender: TObject);
var I: integer;
priority:TThreadPriority;
{ Изменение приоритета соответствующего потока }
begin
priority:=tpIdle;
for i:=0 to ((sender as ttrackbar).position -1) do inc(priority);
if sender=trackbar1 then thread1.priority:=priority
else
if sender=trackbar3 then thread3.priority:=priority
else thread2.Priority:=priority;
end;
16. Завершение (Уничтожение) потоков. Для уничтожения используется деструктор Destroy. Деструктор завершает поток и высвобождает все ресурсы, связанные с объектом TThread.
destructor TMoveThread.Destroy;
begin
Taxi00.free;
Taxi01.free;
inherited Destroy;
end;
17. Запустить подготовленное приложение на выполнение. Несколько раз изменить приоритеты разных потоков и проанализировать реакцию программы. Осуществить приостановку и возобновление каждого из анализируемых потоков.
|