Использование многопоточности в дополнениях Delphi

Лекция

Тема: Создание многотекущих дополнений у ОС Windows

План

Концепция потоков

Внедрение многопоточности в дополнениях Delphi

Пуск потока.

Синхронизации потоков

Критичные секции

Концепция потоков

Потек (thread) - это объект операционной системы, которая являет собой отдельный путь выполнения программки снутри определенного процесса. Каждое дополнение Win32 имеет, по последней мере, один поток, обычно именуемый первичным, либо основным, но программки имеют право создавать дополнительные Использование многопоточности в дополнениях Delphi потоки, созданные для выполнения других заданий.

При помощи потоков реализуются средства одновременного выполнения нескольких различных подпрограмм. Естественно, если компьютер обустроен только одним микропроцессором, то о истинной одновременности работы 2-ух потоков гласить не придется. Но когда для обработки каждого потока операционная система по очереди выделяет определенное время (измеряется Использование многопоточности в дополнениях Delphi в мелких толиках секунды), создается воспоминание одновременной работы нескольких дополнений.

Внедрение многопоточности в дополнениях Delphi

Как следует, давайте определимся, что под словом "потек" мы имеем в виду конкретно Thread, который еще имеет заглавие "нить". Часто встречаются на форумах мысли, что потоки не необходимы вообщем, всякую программку можно написать так, что Использование многопоточности в дополнениях Delphi она будет замечательно работать и без их. Естественно, если не делать ничего серьезнее "Hello World" это так и есть, но если равномерно набирать опыт, в какой-то момент хоть какой программер подойдет к способности "плоского" кода, возникнет необходимость распараллеливать задание. А некие задачки вообщем нельзя воплотить без использования потоков, к Использование многопоточности в дополнениях Delphi примеру работа с сокетами, COM -портом, долгое ожидание каких-то событий, и т.д.

Всем понятно, что Windows система многозадачна. Проще говоря, это означает, что несколько программ могут работать сразу под управлением ОС. Все мы открывали диспетчер заданий и лицезрели перечень процессов. Процесс - это экземпляр выполняемой программки. В Использование многопоточности в дополнениях Delphi реальности сам по для себя он ничего не делает, он создается во время пуска программки, содержит внутри себя служебную информацию, через которую система с ним работает, так же ему выделяется нужная память под код и данные. Для того, чтоб программка заработала, в нем создается поток. Хоть какой процесс Использование многопоточности в дополнениях Delphi содержит внутри себя хотя бы один поток, и конкретно он отвечает за выполнение кода и получает на это процессорное время. Этим и достигается надуманная параллельность работы программ, либо, как ее еще именуют, псевдопараллельность. Почему надуманная? Но поэтому, что реально микропроцессор в каждый момент времени может делать только один участок кода. Windows раздает Использование многопоточности в дополнениях Delphi процессорное время всех потоков в системе по очереди, этим же создается воспоминание, что они работают сразу. Реально работают параллельно потоки могут быть лишь на машинах с 2-мя и больше микропроцессорами.

Для сотворения дополнительных потоков в Delphi существует базисный класс TThread, от него мы и будем наследоваться при реализации собственных Использование многопоточности в дополнениях Delphi потоков. Для того, чтоб сделать "скелет" нового класса, можно избрать в меню File - New - Thread Object, Delphi создаст новый модуль с заготовкой этого класса. Для наглядности, опишем его в модуле формы. Как Вы видите, в этой заготівці прибавлено один способ - Execute. Конкретно его нам и нужно переопределить Использование многопоточности в дополнениях Delphi, код снутри него и будет работать в отдельном потоке. И так, попробуем написать пример - запустим в потоке нескончаемый цикл:

TNewThread = class (TThread)

private

(Private declarations)

protected

procedure Execute; override;

end;

var

Form1: TForm1;

implementation

($ R *. dfm)

(TNewThread)

procedure TNewThread.Execute;

begin

while true do (ничего не делаем);

end;

procedure TForm1.Button1Click (Sender: TObject);

var

NewThread Использование многопоточности в дополнениях Delphi: TNewThread;

begin

NewThread: = TNewThread.Create (true);

NewThread.FreeOnTerminate: = true;

NewThread.Priority: = tpLower;

NewThread.Resume;

end;

Запустите пример на выполнение и нажмите кнопку. Как бы ничего не происходит - форма не зависшая, реагирует на перемещение. В реальности это не так - откройте диспетчер заданий и вы увидите, что микропроцессор загружен стопроцентно. На Использование многопоточности в дополнениях Delphi данный момент в процессе вашего приложения работает два потока - один был сотворен поначалу, во время пуска программки. 2-ой, который так грузит микропроцессор, - мы сделали после нажатия кнопки. Как следует, давайте разберем, что все-таки значит код в Button1Click:

NewThread: = TNewThread.Create (true);

тут мы сделали экземпляр класса TNewThread. Конструктор Create Использование многопоточности в дополнениях Delphi имеет всего один параметр - CreateSuspended типа boolean, который показывает, запустить новый поток сходу после сотворения (если false), либо дождаться команды (если true).

New.FreeOnTerminate: = true;

свойство FreeOnTerminate определяет, что потек после выполнения автоматом закончится, объект будет уничтожен, и нам не придется его уничтожать вручную. В нашем примере это Использование многопоточности в дополнениях Delphi не сущность принципиально, так как сам по для себя он никогда не закончится, но пригодится в последующих примерах.

NewThread.Priority: = tpLower;

Свойство Priority, если вы еще не додумались из наименования, устанавливает ценность потока. Каждый поток в системе имеет собственный ценность. Если процессорного времени не хватает, система начинает Использование многопоточности в дополнениях Delphi распределять его в согласовании с ценностями потоков. Свойство Priority может принимать последующие значения:

• tpTimeCritical - критичный

• tpHighest - очень высочайший

• tpHigher - высочайший

• tpNormal - средний

• tpLower - маленький

• tpLowest - очень маленький

• tpIdle - поток работает во время простоя системы

Ставить высочайшие ценности потоков не стоит, если этого не просит задание, так как это очень нагружает систему.

NewThread.Resume;

Пуск потока.

Это был пример сотворения Использование многопоточности в дополнениях Delphi потоков. Но не все так просто. Казалось бы - пишем хоть какой код снутри способа Execute и все, но, потоки имеют одно противное свойство - они ничего не знают друг о друге. Это означает, допустимо, Вы пытаетесь из другого потока поменять свойство какого-нибудь компонента в форме. Как Использование многопоточности в дополнениях Delphi понятно, VCL однопоточный, весь код снутри программки производится поочередно. Допустимо, в процессе работы поменялись какие-то данные снутри классов VCL, система отбирает время у основного потока, передает по кругу другим потокам и возвращает вспять, при всем этом выполнение кода длится с того места, где закончилось. Если мы из собственного Использование многопоточности в дополнениях Delphi потока что-то изменяем, к примеру, на форме, задействовано много устройств снутри VCL (напомним, выполнение основного потока пока "прекращено"), соответственно за этот период времени успеют поменяться любые данные. И тут вдруг время снова отдается основному сгустку, он расслабленно продолжает свое выполнение, но даны уже изменены! К чему это может привести - предугадать нельзя Использование многопоточности в дополнениях Delphi. Вы сможете проверить это тыщу раз, и ничего не случится, а на тыщу 1-ый программка упадет. И это относится не только лишь к взаимодействию дополнительных потоков с основным, да и к взаимодействию потоков меж собой. Писать такие ненадежные программки обычно нельзя.

Синхронизации потоков

Если вы сделали шаблон класса автоматом, то Использование многопоточности в дополнениях Delphi, наверняка, увидели комментарий, какой Delphi расположил в новый модуль. Он гласит: "Methods and properties of objects in visual components can only be used in a method called using Synchronize". Это означает, что воззвание к зрительным компонентам может быть только методом вызова процедуры Synchronize. Давайте разглядим пример, но сейчас Использование многопоточности в дополнениях Delphi наш поток не будет разогревать микропроцессор напрасно, а будет делать что-либо полезное, к примеру, прокручивать ProgressBar на форме. Как параметр в функцию Synchronize передается способ нашего потока, но сам он передается без характеристик. Характеристики можно передать, прибавив поля подходящего типа в описание нашего класса. У нас будет одно поле Использование многопоточности в дополнениях Delphi - тот же прогресс :

TNewThread = class (TThread)

private

Progress: integer;

procedure SetProgress;

protected

procedure Execute; override;

end;

...

procedure TNewThread.Execute;

var

i: integer;

begin

for i: = 0 to 100 do

begin

sleep (50);

Progress: = i;

Synchronize (SetProgress);

end;

end;

procedure TNewThread.SetProgress;

begin

Form1.ProgressBar1.Position: = Progress;

end;

Вот сейчас ProgressBar двигается, и это на сто процентов неопасно Использование многопоточности в дополнениях Delphi. А неопасно вот почему: процедура Synchronize на время приостанавливает выполнение нашего потока, и передает управление головного потока, другими словами SetProgress производится в основном потоке. Это нужно уяснить, так как некие допускают ошибки, выполняя снутри Synchronize долгосрочную работу, при всем этом, что разумеется, форма зависает на долгое время. Потому используйте Synchronize для Использование многопоточности в дополнениях Delphi выведения инфы - тот же движок прогресса, обновления названий компонент и тому схожее

Вы наверняка увидели, что снутри цикла мы используем функцию Sleep. В одинпотоковом дополнении Sleep употребляется изредка, а вот в потоках его использовать очень комфортно. Пример - нескончаемый цикл, пока не выполнится какое-то условие. Если не воткнуть туда Sleep Использование многопоточности в дополнениях Delphi мы будем просто нагружать систему напрасной работой. Так работает Synchronize. Но еще есть один довольно удачный метод передать информацию форме - посылка сообщения. Давайте разглядим и его. Для этого объявим константу:

const

PROGRESS_POS = WM_USER 1;

В объявление класса формы прибавим новый способ, а позже и его реализацию Использование многопоточности в дополнениях Delphi:

TForm1 = class (TForm)

Button1: TButton;

ProgressBar1: TProgressBar;

procedure Button1Click (Sender: TObject);

private

procedure SetProgressPos (var Msg : TMessage); message PROGRESS_POS;

public

(Public declarations)

end;

...

procedure TForm1.SetProgressPos (var Msg : TMessage);

begin

ProgressBar1.Position: = Msg.LParam;

end;

Сейчас мы незначительно изменим, можно сказать даже упростим, реализацию способа Execute нашего потока :

procedure TNewThread.Execute;

var

i: integer Использование многопоточности в дополнениях Delphi;

begin

for i: = 0 to 100 do

begin

sleep (50);

SendMessage (Form1.Handle, PROGRESS_POS, 0, i);

end;

end;

Используя функцию SendMessage, мы посылаем окну программки сообщения, один из характеристик которого содержит подходящий нам прогресс. Сообщение становится в очередь, и в согласовании с этой очередью будет обработано основным потоком, где и выполнится способ Использование многопоточности в дополнениях Delphi SetProgressPos. Но тут есть один аспект: SendMessage, как и в случае с Synchronize, остановит выполнение нашего потока, пока основной поток не обработает сообщения. Если использовать PostMessage этого не случится, наш поток вышлет сообщение и продолжит свою работу, а уже когда оно там будет проработано - непринципиально. Какую из этих функций использовать - решать Использование многопоточности в дополнениях Delphi вам, все находится в зависимости от задания.

Вот, в принципе, мы и разглядели главные методы работы с компонентами VCL из потоков. Как быть, если в нашей программке не один новый поток, а несколько? И необходимо организовать работу с одними и теми же данными? Тут нам на помощь Использование многопоточности в дополнениях Delphi приходят другие методы синхронизации. Какой-то из них мы и разглядим. Для его реализации необходимо прибавить в проект модуль SyncObjs.

Критичные секции

Работают они таким методом: снутри критичной секции может работать только один поток, другие ждут его окончания. Чтоб лучше осознать, всюду приводят сопоставления с узенькой трубой: представьте, с одной стороны "толпятся" потоки Использование многопоточности в дополнениях Delphi, но в трубу может "пролізти" только один, а когда он "пролізе" - начнет движение 2-ой, и так по порядку. Еще проще осознать это на примере и этим же ProgressBar 'ом. Как следует, запустите один из примеров, приведенных ранее. Нажмите на кнопку, подождите несколько секунд, а позже нажмите снова. Что происходит Использование многопоточности в дополнениях Delphi? ProgressBar начал прыгать. Прыгает поэтому, что у нас работает не один поток, а два, и любой из их передает различные значения прогрессу. Сейчас малость переделаем код, в событии onCreate формы сделаем критичную секцию:

var

Form1: TForm1;

CriticalSection: TCriticalSection;

...

procedure TForm1.FormCreate (Sender: TObject);

begin

CriticalSection: = TCriticalSection.Create;

end;

У TCriticalSection Использование многопоточности в дополнениях Delphi есть две необходимы нам способу, Enter и Leave, соответственно вход и выход из нее. Поместим наш код в критичную секцию:

procedure TNewThread.Execute;

var

i: integer;

begin

CriticalSection.Enter;

for i: = 0 to 100 do

begin

sleep (50);

SendMessage (Form1.Handle, PROGRESS_POS, 0, i);

end;

CriticalSection.Leave;

end;

Попытайтесь запустить программку и надавить пару раз Использование многопоточности в дополнениях Delphi на кнопку, а позже посчитайте, сколько раз пройдет прогресс. Понятно, в чем сущность? 1-ый раз, нажимая на кнопку, мы создаем поток, он занимает критичную секцию и начинает работу. Жмем 2-ой - создается 2-ой поток, но критичная секция занята, и он ждет, пока ее не высвободит 1-ый. 3-ий, 4-ый - все пройдут только Использование многопоточности в дополнениях Delphi по-черзі.

Критичные секции комфортно использовать при обработке одних и тех же данных (списков, массивов) различными потоками.

Контрольные вопросы

1. Что такое потек?

2. Какие Вы понимаете типы многозадачности у ОС Windows?

3. Что такое процесс?

4. В чем отличие потока от процесса?

5. Зачем нужная процедура Synchronize?

6. Зачем нужны критичные секции?

7. Какие Использование многопоточности в дополнениях Delphi Вы понимаете ценности потоков?

8. Зачем нужный способ Execute?

9. Как можно найти количество потоков в запущенном процессе?

Литература

1.Матчо Дж. Delphi 2: Управление для экспертов: Пер. из англ.- Спб.: Вvh -сант-петербург, 1997.-784 с.

2.СкусновА.Л. Справочник по компонентам Delphi 3.-М.: Приор, 1998.-288 с.

3. Культін н.Б. Программирование в Турбо Pascal 7.0 и Delphi: (Учебник) -СПб.: Вvh Использование многопоточности в дополнениях Delphi -сант-петербург, 1999.-234 с.

4 . Епанешников А. М., Епанешников в.А. Программирование в среде Delphi : Учебный Посібник.-м.: Диалог МИФЕ.,1997.- Ч4. Работа с базами данных. Организация справочной системи.-1998.-400 с.

5. Бобровський с.Н. Delphi 5: Учебный курс.-СПб: ДЕСС: Інфорком-пресс, 2000.-638 с.

6.Архангельский а.Я. 100 компонент общего предназначения библиотеки Delphi 5.-М.: Двучлен, 1999.-266 с.

7.Епанешников Использование многопоточности в дополнениях Delphi А. М., Епанешников в.А. Delphi5. Базы Даних.-м : ДИАЛОГОВОМ МИФЕ, 2000.-416 с.


ispolzovanie-elektronnih-servisov.html
ispolzovanie-elektronnoj-pochti-referat.html
ispolzovanie-elementov-prirodi-pri-oformlenii-intererov-gostinic-dekorativnoe-oformlenie-pomeshenij.html