Для организации локальной петли сообщений существует метод Application.ProcessMessages
. Он вызывает ProcessMessage
до тех пор, пока очередь не окажется пустой. Вызов этого метода рекомендуется вставлять в обработчики событий, которые работают долго, чтобы в это время программа не теряла способности реагировать на действия пользователя.
Из сказанного может сложиться впечатление, что главная нить проверяет список методов синхронизации только в главной петле сообщений, когда вызывается метод Idle
. На самом деле это не так. Модуль Classes
содержит переменную WakeMainThread
, хранящую указатель на метод, который вызывается при помещении нового метода в список синхронизации. В конструкторе TApplication
этой переменной присваивается указатель на метод TApplication.WakeMainThread
, который посылает сообщение WM_NULL
невидимому окну приложения. Сообщение WM_NULL
— это "пустое" сообщение, на которое окно не должно реагировать (оно используется, например, при перехвате сообщений ловушкой: ловушка не может запретить передачу окну сообщения, но может изменить его на WM_NULL
, чтобы окно проигнорировало сообщение). Невидимое окно приложения, тем не менее, не игнорирует это сообщение, а вызывает при его получении CheckSynchronize
. Таким образом, синхронное выполнение метода не откладывается до вызова Idle
, а выполняется достаточно быстро, в том числе и в локальной петле сообщений. Более того, если главная нить перешла в режим ожидания получения сообщения (через вызов WaitMessage
), то вызов Synchronize
в другой нити прервет это ожидание, т.к. в очередь будет поставлено сообщение WM_NULL
.
Процедура CheckSynchronize
и переменная WakeMainThread
позволяют обеспечить синхронизацию и в тех приложениях, которые не используют VCL в полном объеме. Разработчику приложения необходимо обеспечить периодические вызовы функции CheckSynchronize
из главной нити, чтобы можно было вызывать TThread.Synchronize
в других нитях. При этом в главной нити можно обойтись без петли сообщений. Присвоение переменной WakeMainThread
собственного метода позволяет реализовать специфичный для данного приложения способ ускорения вызова метода в главной нити.
Примечание
Описанный здесь способ синхронизации работы нитей появился, начиная с шестой версии Delphi. В более ранних версиях списка методов для синхронизации не было. Вместо этого в главной нити создавалось специальное невидимое окно, а метод TThread.Synchronize
с помощью SendMessage
посылал этому окну сообщение CM_EXECPROC
с адресом объекта, метод которого нуждался в синхронизации. Метод выполнялся в оконной процедуре данного окна при обработке этого сообщения. Такой механизм также позволял осуществить синхронизацию в приложениях без VCL. но требовал обязательного наличия петли сообщений в главной нити и не давал возможности выполнять синхронизацию, пока главная нить находилась в локальной петле сообщений. Из-за смены механизма синхронизации могут возникнуть проблемы при переносе в новые версии старых приложений: если раньше для обеспечения работы синхронизации было достаточно организовать петлю сообщений, то теперь необходимо найти место для вызова CheckSynchronize
. Разумеется, при переносе полноценных VCL-приложений эти проблемы не возникают, т.к. все, что нужно, содержится в методах класса TApplication
.
Принятый в Delphi 6 способ синхронизации получил дальнейшее развитие в BDS 2006. В классе TThread появился метод Queue
для передачи в код главной нити вызов метода для асинхронного выполнения, т.е. такого, когда нить вызвавшая Queue
, после этого продолжает работать, не дожидаясь, пока главная нить выполнит требуемый код. Главная нить выполняет этот код параллельно тогда, когда для этого предоставляется случай (информация получена из анализа исходных кодов модулей VCL, т.к. справка Delphi, к сожалению не описывает данный метод: в справке BDS 2006 он вообще не упомянут, в справке Delphi 2007 упомянут, но все описание состоит из одной фразы "This is Queue, а member of class TThread"). Метод Queue
использует тот же список методов синхронизации, что и Synchronize
, только элементы этого списка пополнились признаком асинхронного выполнения и процедура CheckSynchronize
не уведомляет нить, поместившую метод в список, о его выполнении, если метод помещен в список синхронизации методом Queue
. А метод TThread.RemoveQueuedEvents
позволяет удалять из списка методов синхронизации асинхронные вызовы, если нужда в их выполнении отпала.
Читать дальше
Конец ознакомительного отрывка
Купить книгу