Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Параллельные потоки.doc
Скачиваний:
2
Добавлен:
03.09.2019
Размер:
188.93 Кб
Скачать

Взаимодействие с vcl-потоком

Сначала рассмотрим взаимодействие параллельных потоков с основным VCL-потоком, а затем взаимодействие параллельных потоков между собой. Как уже было отмечено, библиотека VCL не является потокобезопасной, поэтому недопустимо вызывать методы и изменять свойства визуальных компонентов из параллельных потоков. Для решения задачи синхронизации Delphi-класс TThread имеет метод Synchronize. В классе TGsvThread будет использован другой способ взаимодействия, который мне кажется более удобным. Взаимодействия с основным потоком может быть синхронным и асинхронным. Первый тип взаимодействия реализуется с помощью посылки синхронного оконного сообщения - SendMessage, а второй - с помощью асинхронного оконного сообщения - PostMessage. В первом случае выполнение параллельного потока, вызвавшего SendMessage, приостанавливается и управление передается средствами операционной системы основному потоку приложения, вызывается процедура окна, дескриптор которого был передан в функцию SendMessage и диспетчер сообщений окна вызывает тот метод формы, который связан с идентификатором сообщения. Рассмотрим простейший пример, в котором форма отображает с помощью компонента TLabel целое число, которое инкрементируется с некоторым интервалом в параллельном потоке.

procedure TThreadCounter.Execute;

var

i: Integer;

begin

i := 0;

while not Terminated do begin

Pause(500);

Inc(i);

SendMessage(FFormHandle, WM_THREAD_COUNTER, i, LPARAM(Self));

end;

end;

Дескриптор окна передается конструктору объекта TThreadCounter и используется для посылки синхронного сообщения, причем значение счетчика передается как WParam, а в LParam передается сам объект параллельного потока. Для приема этого сообщения в форме должна быть определена такая процедура:

const

WM_THREAD_COUNTER = WM_USER + 1000;

....

procedure OnThreadCounter(var aMessage: TMessage);

message WM_THREAD_COUNTER;

....

procedure TForm1.OnThreadCounter(var aMessage: TMessage);

begin

lblCounter.Caption := IntToStr(aMessage.WParam);

end;

В процедуре OnThreadCounter используется только значение счетчика, хотя можно безопасно использовать и сам объект потока, так как при синхронном сообщении он приостановлен и его состояние не может измениться.

Асинхронное взаимодействие с VCL-потоком выполняется с помощью функции PostMessage. В отличие от SendMessage, вызывающий поток не приостанавливается, а сообщение просто заносится в очередь сообщений основного потока, в контексте которого выполняются оконные процедуры всех VCL-форм. В PostMessage мы уже не имеем права передавать ссылку на объект потока, так как поток может быть уничтожен до того момента, как будет обработано оконное сообщение, но вот дескриптор параллельного потока можно передать без всякого опасения.

Двух указанных способов вполне достаточно для организации взаимодействия параллельных потоков с основным VCL-потоком, причем с минимальными трудозатратами - так же, как и при использовании Synchronize, нам нужно определить всего один метод. В отличие от Synchronize, метод определяется не в классе потока, а в классе формы - это кажется мне более удобным решением. Хотя есть и не очень эстетичный момент - необходимость явного приведения типов WParam и LParam к действительным типам передаваемых данных, которого в общем случае желательно избегать.