Средства синхронизации потоков
Проще всего говорить о синхронизации, если создаваемый поток не взаимодействует с ресурсами других потоков и не обращается к 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).
Косвенно к этой группе может быть добавлена критическая секция
(critical section).
Примечание
Перечисленные выше средства синхронизации
в основном инкапсулированы в состав классов Delphi. У программиста есть две
альтернативы. С одной стороны, в состав библиотеки VCL включен модуль SYNCOBJS.PAS,
содержащий классы для события (TEvent)
и критической секции (TCriticalSection).
С другой, с Delphi поставляется отличный пример IPCDEMOS,
который иллюстрирует проблемы взаимодействия процессов и содержит модуль IPCTHRD.PAS
с аналогичными классами — для того же события, взаимного исключения (TMutex),
а также совместно используемой памяти (TSharedMem).
Перейдем к подробному описанию объектов, используемых для синхронизации.
|