на тему рефераты Информационно-образоательный портал
Рефераты, курсовые, дипломы, научные работы,
на тему рефераты
на тему рефераты
МЕНЮ|
на тему рефераты
поиск
Робота з "потоками" в середовищі Delphi
p align="left">До того ж Windows 2000 Professional і Windows 2000 Server мають різні алгоритми виділення квантів часу. Перша - клієнтська - операційна система виділяє час короткими квантами змінної довжини для прискорення реакції на додатки переднього плану (foreground). Для серверу ж більш важлива стабільна робота системних служб, тому в другій ОС система розподіляє довгі кванти постійної довжини.

Мал. 29.1. За допомогою діалогу Performance Options можна управляти алгоритмом призначення пріоритетів

Тепер, розібравшись в пріоритетах потоків, потрібно обов'язково сказати про те, як же їх використовує планувальник завдань для розподілу процесорного часу.

Операційна система має різні черги готових до виконання потоків - для кожного рівня пріоритету свій. У момент розподілу нового кванта часу вона проглядає черги - від вищого пріоритету до нижчого. Готовий до виконання потік, що стоїть першим в черзі, одержує цей квант і переміщається в хвіст черги. Потік виконуватиметься всю тривалість кванта, якщо не відбудеться одна з двох подій:

· потік, що виконується, зупинився для очікування;

· з'явився готовий до виконання потік з вищим пріоритетом.

Тепер, напевно, вам більш ясна небезпека, витікаюча від невиправданого завищення пріоритетів. Адже, якщо є активні потоки з високим пріоритетом, жоден потік з нижчим пріоритетом жодного разу не одержить часу процесора. Ця проблема може підстерігати вас навіть на рівні вашого додатку. Припустимо, ви призначили обчислювальному потоку пріоритет THREAD_PRIORITY_ABOVE_NORMAL, а потоку, де обробляється введення користувача, - THREAD_PRIORITY_BELOW_NORMAL. Тоді замість запланованого результату - сумістити обчислення з нормальною реакцією додатку - ви одержите строго зворотний. Додаток взагалі перестане відгукуватися на введення, і зняти його буде можливо тільки за допомогою засобів ОС.

Отже нормальна практика для асиметричних потоків - це призначення потоку, оброблювальному введення, вищого пріоритету, а всім іншим - нижчого або навіть пріоритету idle, якщо цей потік повинен виконуватися тільки під час простою системи.

Клас TThread

Delphi представляє програмісту повний доступ до можливостей програмування інтерфейсу Win32. Для чого ж тоді фірма Borland представила спеціальний клас для організації потоків? Взагалі кажучи, програміст не зобов'язаний розбиратися у всій тонкості механізмів, пропонованих операційною системою. Клас повинен інкапсулювати і спрощувати програмний інтерфейс; клас TThread - прекрасний приклад надання розробнику простого доступу до програмування потоків. Сам API потоків, взагалі кажучи, не дуже складний, але надані класом TThread можливості взагалі чудово прості. Двома словами, все, що вам необхідно зробити, - це перекрити віртуальний метод Execute.

Інша відмінна риса класу TThread - це гарантія безпечної роботи з бібліотекою візуальних компонентів VCL. Без використовування класу TThread під час викликів VCL можуть виникнути ситуації, що вимагають спеціальної синхронізації (див. разд. «Проблеми при синхронізації потоків» далі в цьому розділі).

Потрібно віддавати собі звіт, що з погляду операційної системи потік - це її об'єкт. При створенні він одержує дескриптор і відстежується ОС. Об'єкт класу TThread - це конструкція Delphi, відповідна потоку ОС. Цей об'єкт VCL створюється до реального виникнення потоку в системі і знищується після його зникнення.

Вивчення класу TThread почнемо з методу Execute:

procedure Execute; virtual; abstract;

Це і є код, виконуваний в створюваному вами потоці TThread.

Примітка

Хоча формальний опис Execute - метод abstract, але майстер створення нового об'єкту TThread створює для вас порожній шаблон цього методу.

Метод Execute, ми можемо тим самим закладати в новий потоковий клас те, що виконуватиметься при його запуску. Якщо потік був створений з аргументом CreateSuspended, рівним False, то метод Execute виконується негайно, інакше Execute виконується після виклику методу Resume (див. опис конструктора нижче).

Якщо потік розрахований на одноразове виконання яких-небудь дій, то ніякого спеціального коду завершення усередині Execute писати не треба.

Якщо ж в потоці виконуватиметься якийсь цикл, і потік повинен завершитися разом з додатком, то умови закінчення циклу повинні бути приблизно такими:

procedure TMyThread. Execute;

begin

repeat

DoSomething;

Until CancelCondition or Terminated;

end;

Тут CancelCondition - ваша особиста умова завершення потоку (вичерпання даних, закінчення обчислень, надходження на вхід того або іншого символу і т.п.), а властивість Terminated повідомляє про завершення потоку (ця властивість може бути встановлене як зсередини потоку, так і ззовні; швидше за все, завершується його процес, що породив).

Конструктор об'єкту:

constructor Create (CreateSuspended: Boolean);

одержує параметр CreateSuspended. Якщо його значення рівне True, знов створений потік не починає виконуватися до тих пір, поки не буде зроблений виклик методу Resume. У випадку, якщо параметр CreateSuspended має значення False, конструктор завершується і тільки тоді потік починає виконання.

destructor Destroy; override;

Деструкція Destroy викликається, коли необхідність в створеному потоці відпадає. Деструкція завершує його і вивільняє всі ресурси, пов'язані з об'єктом TThread. function Terminate: Integer;

Для остаточного завершення потоку (без подальшого запуску) існує метод Terminate. Але якщо ви думаєте, що цей метод робить якісь примусові дії по зупинці потоку, ви помиляєтеся. Все, що відбувається, - це установка властивості

property Terminated: Boolean;

у значення True. Таким чином, Terminate - це вказівка потоку завершитися, виражене «в м'якій формі», з можливістю коректно звільнити ресурси. Якщо вам потрібно негайно завершити потік, використовуйте функцію Windows API TerminateThread.

Примітка

Метод Terminate автоматично викликається і з деструкції об'єкту. Поток - об'єкт VCL чекатиме, поки завершиться поток - об'єкт операційної системи. Таким чином, якщо потік не уміє завершуватися коректно, виклик деструкції потенційно може привести до зависання всієї програми.

Ще одна корисна властивість:

property FreeOnTerminate: Boolean;

Якщо це властивість рівне True, то деструкція потоку буде викликана автоматично після його завершення. Це дуже зручно для тих випадків, коли ви в своїй програмі не упевнені точно, коли саме завершиться потік, і хочете використовувати його за принципом «вистрілив і забув» (fire and forget).

function WaitFor: Integer;

Метод WaitFor призначений для синхронізації і дозволяє одному потоку дочекатися моменту, коли завершиться інший потік. Якщо ви усередині потоку FirstThread пишіть код

Code:= SecondThread. WaitFor;

то це означає, що потік FirstThread зупиняється до моменту завершення потоку SecondThread. Метод WaitFor повертає код завершення очікуваного потоку (див. властивість Returnvalue).

property Handle: THandle read FHandle;

property ThreadID: THandle read FThreadID;

Властивості Handle і ThreadID дають програмісту безпосередній доступ до потоку засобами API Win32. Якщо розробник хоче звернутися до потоку і управляти ним, минувши можливості класу TThread, значення Handle і ThreadID можуть бути використані як аргументи функцій Win32 API. Наприклад, якщо програміст хоче перед продовженням виконання додатку дочекатися завершення відразу декількох потоків, він повинен викликати функцію API waitForMuitipieObjects; для її виклику необхідний масив дескрипторів потоків.

property Priority: TThreadPriority;

Властивість Priority дозволяє запитати і встановити пріоритет потоків. Пріоритети потоків в деталях описані вище. Допустимими значеннями пріоритету для об'єктів TThread є tpidle, tpLowest, tpLower, tpNormai, tpHigher, tpHighest і tpTimeCritical.

procedure Synchronize (Method: TThreadMethod);

Цей метод відноситься до секції protected, тобто може бути викликаний тільки з нащадків TThread. Delphi надає програмісту метод Synchronize для

безпечного виклику методів VCL усередині потоків. Щоб уникнути конфліктних ситуацій, метод synchronize дає гарантію, що до кожного об'єкту VCL одночасно має доступ тільки один потік. Аргумент, передаваний в метод Synchronize, - це ім'я методу, який виробляє звернення до VCL; виклик Synchronize з цим параметром - це те ж, що і виклик самого методу. Такий метод (класу TThreadMethod) не повинен мати ніяких параметрів і не повинен повертати ніяких значень. Наприклад, в основній формі додатку потрібно передбачити функцію

procedure TMainForm. SyncShowMessage; begin

ShowMessagedntToStr (ThreadListl. Count)); // інші звернення до VCL

end;

а в потоці для показу повідомлення писати не

ShowMessage (IntToStr(ThreadListl. Count));

і навіть не

MainForm. SyncShowMessage;

а тільки так:

Synchronize (MainForm. SyncShowMessage);

Примітка

Виробляючи будь-яке звернення до об'єкту VCL з потоку, переконайтеся, що при цьому використовується метод Synchronize; інакше результати можуть виявитися непередбачуваними. Це вірно навіть в тому випадку, якщо ви використовуєте засоби синхронізації, описані нижче.

procedure Resume;

Метод Resume класу TThread викликається, коли потік відновлює виконання після зупинки, або для явного запуску потоку, створеного з параметром CreateSuspended, рівним True.

procedure Suspend;

Виклик методу Suspend припиняє потік з можливістю повторного запуску згодом. Метод suspend припиняє потік незалежно від коду, виконуваного потоком в даний момент; виконання продовжується з точки останову.

property Suspended: Boolean;

Властивість suspended дозволяє програмісту визначити, чи не припинений потік. За допомогою цієї властивості можна також запускати і зупиняти потік. Встановивши властивість suspended в значення True, ви одержите той же результат, що і при виклику методу Suspend - припинення. Навпаки, установка властивості Suspended в значення False відновлює виконання потоку, як і виклик методу Resume.

property ReturnValue: Integer;

Властивість ReturnValue дозволяє взнати і встановити значення, що повертається потоком після його завершення. Ця величина повністю визначається користувачем. За умовчанням потік повертає нуль, але якщо програміст захоче повернути іншу величину, то просте встановлення заново властивості ReturnValue усередині потоку дозволить одержати цю інформацію іншим потокам. Це, наприклад, може стати в нагоді, якщо усередині потоку виникли проблеми, або за допомогою властивості ReturnValue потрібно повернути число не минулих орфографічну перевірку слів.

На цьому завершимо докладний огляд класу TThread. Для ближчого знайомства з потоками і класом Delphi TThread створимо багатопотоковий додаток. Для цього потрібно написати всього декілька рядків коду і кілька разів клацнути мишею.

Засоби синхронізації потоків

Простіше всього говорити про синхронізацію, якщо створюваний потік не взаємодіє з ресурсами інших потоків і не звертається до VCL. Припустимо, у вас на комп'ютері декілька процесорів, і ви хочете «розпаралелювати» обчислення. Тоді цілком доречний наступний код:

MyCompThread:= TComputationThread. Create(False);

 // Тут можна що-небудь робити, поки другий потік виробляє обчислення

DoSomeWork;

 // Тепер чекаємо його завершення

MyCompThread. WaitFor;

Приведена схема абсолютно недопустима, якщо під час своєї роботи потік MyCompThread звертається до VCL за допомогою методу synchronize. В цьому випадку потік чекає головного потоку для звернення до VCL, а той, у свою чергу, його - класична безвихідь.

За «порятунком» слід звернутися до програмного інтерфейсу Win32. Він надає багатий набір інструментів, які можуть знадобитися для організації спільної роботи потоків.

Головні поняття для розуміння механізмів синхронізації - функції очікування і об'єкти синхронізації. У Windows API передбачений ряд функцій, що дозволяють припинити виконання потоку, що викликав цю функцію, аж до того моменту, як буде змінений стан якогось об'єкту, званого об'єктом синхронізації (під цим терміном тут розуміється не об'єкт Delphi, а об'єкт операційної системи). Проста з цих функцій - waitForSingieCbject - призначена для очікування одного об'єкту.

До можливих варіантів відносяться чотири об'єкти, які розроблені спеціально для синхронізації: подія (event), взаємне виключення (mutex), семафор (semaphore) і таймер (timer).

Але окрім спеціальних об'єктів можна організувати очікування і інших об'єктів, дескриптор яких використовується в основному для інших цілей, але може застосовуватися і для очікування. До них відносяться: процес (process), потік (thread), сповіщення про зміну у файловій системі (change notification) і консольне введення (console input).

Страницы: 1, 2, 3



© 2003-2013
Рефераты бесплатно, курсовые, рефераты биология, большая бибилиотека рефератов, дипломы, научные работы, рефераты право, рефераты, рефераты скачать, рефераты литература, курсовые работы, реферат, доклады, рефераты медицина, рефераты на тему, сочинения, реферат бесплатно, рефераты авиация, рефераты психология, рефераты математика, рефераты кулинария, рефераты логистика, рефераты анатомия, рефераты маркетинг, рефераты релиния, рефераты социология, рефераты менеджемент.