Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Простейший поток




 

Давайте попробуем написать простейший поток и в процессе познакомимся с его возможностями и как всё реализовано.

Создайте новый проект. Поставьте на форму компонент ТRichEdit из палитры Win32 и один компонент TLabel. Нам ещё понадобиться пару кнопок – одна для запуска потока, другая для его остановки (рис. 5.1.).

 

Рис. 5.1. Главная форма программы

 

Теперь создадим модуль для потока. Для этого выберите пункт меню File->New- >Other для открытия окна создания нового модуля (рис. 5.2).

Найдите в этом окне на закладке New пункт Thread Object. Выделите его и нажмите кнопку "ОК". Появляется окошко, как на рис. 5.3. В этом окне нужно указать имя создаваемого потока. Мы назвали свой поток TCountObj. Нажмите «ОК» и Delphi создаст модуль-заготовку для нашего будущего потока. Сохраните весь проект. Главную форму под именем Main, а поток под именем MyThread.

Рис. 5.2. Создание модуля потока

 

Рис. 5.3. Задание имени потока

 

Теперь посмотрим на код созданного для потока модуля:

unit MyThread;

interface

uses

Classes;

type

TCountObj = class(TThread)

private

{ Private declarations }

protected

procedure Execute; override;

end;

implementation

 

{ Important: Methods and properties of objects in VCL can only be used in a method called using Synchronize, for example,

}

Synchronize(UpdateCaption);

and UpdateCaption could look like,

procedure TCountObj.UpdateCaption;

begin

Form1.Caption:= 'Updated in a thread';

end; }

{ TCountObj }

procedure TCountObj.Execute;

begin

{ Place thread code here }

end;

end.

 

Это новый поток. У объекта есть только одна процедура Execute. В любых потоках эта процедура обязана быть переопределена, и в ней должен быть написан собственный код. Это связано с тем, что в объекте TThread, эта процедура объявлена как абстрактная (abstract) – пустая. Это значит, что процедуре дали имя, выделили место, но её код должен быть написан объектами потомками, т.е. нами. Метод Execute – это и есть заготовка для кода потока. То, что мы напишем здесь, будет выполняться параллельно основной задаче. Давайте напишем здесь следующий код:

 

procedure TCountObj.Execute;

begin

index:=1;

// Запускаем бесконечный счётчик

while index>0 do

begin

Synchronize(UpdateLabel);

Inc(index);

if index>100000 then

index:=0;

// Если поток остановлен, то выйти.

if terminated then exit;

end;

end;

 

Переменную index мы объявили как integer в разделе private объекта потока. Там же мы объявили процедуру UpdateLabel. Эта процедура выглядит так:

 

procedure TCountObj.UpdateLabel;

begin

Form1.Label1.Caption:=IntToStr(Index);

end;

И последнее, что мы сделали - подключили главную форму в раздел uses, потому что мы обращаемся к ней в коде выше (Form1.Label1.Caption) для обновления текста компонента Label1. В методе Execute у нас запускается цикл while, который будет выполняться, пока переменная index больше нуля. Внутри цикла мы вызывали метод Synchronize (о нём чуть позже) и увеличили переменную index. Если эта переменная становиться больше 100000, то в index присваивается 0, и расчёт начинается с начала. Таким образом цикл будет бесконечно выполнять увеличение переменной index от 0 до 100000 и опять сначала. Самой последней идёт проверка, если свойство terminated равно true, то выйти из процедуры. Когда мы выйдём, то работа потока закончится, потому что закончится код процедуры Execute. Свойство terminated станет равной true тогда, когда будет вызван метод Terminate нашего потока. Теперь о функции Synchronize. В качестве параметра ей передаётся процедура UpdateLabel, которая производит вывод в главную форму. Для чего нужно вставлять процедуру вывода на экран в Synchronize? Библиотека VCL имеет один недостаток - она не защищена от потоков. Все пользовательские компоненты разрабатывались так, что к ним может получить доступ только один поток. Если главная форма и поток попробуют одновременно вывести что-нибудь в одну и ту же область экрана или компонент, то программа выдаст ошибку. Поэтому весь вывод на форму нужно выделять в отдельную процедуру и вызывать эту процедуру с помощью Synchronize.

Если процедура вызвана в методе Synchronize, то выполнение основной программы и потока останавливается, и к компонентам окна получает доступ только объект, вызвавший метод Synchronize. Этот процесс незаметен для пользователя. Так что если вам нужно вывести какие-то данные из потока на экран главного окна, то делайте это в отдельной процедуре и вызывайте её с помощью метода Synchronize. Всё, наш поток готов. Возвращаемся к главной форме. В раздел uses (самый первый, который идёт после interface) мы добавили модуль потока MyThread. Добавление модуля в первый раздел uses связано с тем, что в разделе private нам нужно объявить переменную, имеющую тип нашего объекта. Если добавить имя модуля во второй раздел uses, то он находится ниже той части кода, где нам нужно написать объявление. Именно поэтому добавлять модуль MyThread нужно в первый раздел uses.

В разделе private мы объявилм переменную «co»типа TCountObj (объект нашего потока).

По нажатию кнопки "Запустить" мы написали такой код:

procedure TForm1.Button1Click(Sender: TObject);

begin

co:=TCountObj.Create(true);

co.Resume;

co.Priority:=tpLower;

end;

В первой строке мы создаем поток co. В качестве параметра может быть true или false.

Если false, то поток сразу начинает выполнение, иначе поток создаётся, но не запускается.

Если поток создан не запущенным, то для запуска нужно использовать метод Resume, что мы делаем во второй строке.

В третьей строке мы устанавливаем приоритет потока поменьше, чтобы он не мешал работе основному потоку и выполнялся в фоне. Если установить приоритет повыше, то основной поток начнёт притормаживать, потому что у них будут одинаковые приоритеты.

По нажатию кнопки " Остановить " мы написали:

 

procedure TForm1.Button1Click(Sender: TObject);

begin

co.Terminate;

end;

 

Здесь мы останавливаю выполнение потока с помощью вызова метода Terminate объекта потока. После вызова этого метода свойство terminated станет равным true, и выполнение процедуры Execute закончится.

Попробуйте запустить эту программу, запустить поток (нажатием кнопки " Запустить ") и понабирать текст в RichEdit. Текст будет набираться без проблем, и в это время в компоненте ТLabel будет работать счётчик. Если бы вы запустили счётчик без отдельного потока, то вы бы не смогли набирать текст в RichEdit, потому что все ресурсы программы (основного потока) уходили бы на работу счётчика.

 




Поделиться с друзьями:


Дата добавления: 2015-03-29; Просмотров: 388; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.018 сек.