Реферат: Робота з "потоками" в середовищі Delphi
Приведена схема абсолютно недопустима, якщо під час своєї роботи потік MyCompThread звертається до VCL за допомогою методу synchronize. В цьому випадку потік чекає головного потоку для звернення до VCL, а той, у свою чергу, його – класична безвихідь.
За «порятунком» слід звернутися до програмного інтерфейсу Win32. Він надає багатий набір інструментів, які можуть знадобитися для організації спільної роботи потоків.
Головні поняття для розуміння механізмів синхронізації – функції очікування і об'єкти синхронізації. У Windows API передбачений ряд функцій, що дозволяють припинити виконання потоку, що викликав цю функцію, аж до того моменту, як буде змінений стан якогось об'єкту, званого об'єктом синхронізації (під цим терміном тут розуміється не об'єкт Delphi, а об'єкт операційної системи). Проста з цих функцій – waitForSingieCbject – призначена для очікування одного об'єкту.
До можливих варіантів відносяться чотири об'єкти, які розроблені спеціально для синхронізації: подія (event), взаємне виключення (mutex), семафор (semaphore) і таймер (timer).
Але окрім спеціальних об'єктів можна організувати очікування і інших об'єктів, дескриптор яких використовується в основному для інших цілей, але може застосовуватися і для очікування. До них відносяться: процес (process), потік (thread), сповіщення про зміну у файловій системі (change notification) і консольне введення (console input).
Побічно до цієї групи може бути додана критична секція (critical section).
Примітка
Перераховані вище засоби синхронізації в основному інкапсульовані до складу класів Delphi. У програміста є дві альтернативи. З одного боку, до складу бібліотеки VCL включений модуль SYNCOBJS.PAS, що містить класи для події (TEvent) і критичної секції (TCriticalSection). З іншою, з Delphi поставляється відмінний приклад IPCDEMOS, який ілюструє проблеми взаємодії процесів і містить модуль IPCTHRD.PAS з аналогічними класами – для тієї ж події, взаємного виключення (TMutex), а також спільно використовуваної пам'яті (TSharedMem).
Перейдемо до докладного опису об'єктів, використовуваних для синхронізації.
Подія
Об'єкт типу подія (event) – простий вибір для задач синхронізації. Він подібний дверному дзвінку – дзвенить до тих пір, поки його кнопка знаходиться в натиснутому стані, сповіщаючи про цей факт оточуючих. Аналогічно, і об'єкт може бути в двох станах, а «чути» його можуть багато потоків відразу. Клас TEvent (модуль SYNCOBJS.PAS) має два методи: setEvent і ResetEvent, які переводять об'єкт в активний і пасивний стан відповідно. Конструктор має наступний вигляд:
constructor Create (EventAttributes: PSecurityAttributes;
ManualReset, InitialState: Boolean; const Name: string);
Тут параметр initialstate – початковий стан об'єкту, ManualReset – спосіб його скидання (перекладу в пасивний стан). Якщо цей параметр рівний True, подія повинна бути скинуте уручну. Інакше подія скидається у міру того, як стартує хоч один потік, що чекав даного об'єкту.
На третьому методі:
TWaitResult = (wrSignaled, wrTimeout, wrAbandoned, wrError);
function WaitFor (Timeout: DWORD): TWaitResult;
зупинимося докладніше. Він дає можливість чекати активізації події протягом Timeout мілісекунд. Як ви могли здогадатися, усередині цього методу відбувається виклик функції waitFotsingieObject. Типових результатів на виході waitFor два – wrsignaied, якщо відбулася активізація події, і wrTimeout, якщо за час тайм-ауту нічого не відбулося.
Примітка
Якщо потрібно (і допустимо!) чекати нескінченно довго, слід встановити параметр Timeout в значення INFINITE.
Розглянемо маленький приклад. Включимо до складу нового проекту об'єкт типа TThread, наповнивши його метод Execute наступним вмістом:
Var res: TWaitResult;
procedure TSimpleThread. Execute;
begin
e:= TEvent. Create (nil, True, false, 'test');
repeat
e. ReSetEvent;
res:= e. WaitFor(10000);
Synchronize(Showlnfo);