Читайте также:
|
|
При использовании в приложении нескольких потоков необходимо гарантировать, что в данный момент только один из потоков может иметь доступ к свойствам и методам объекта VCL - визуального компонента Delphi, то есть действия потоков необходимо синхронизировать между собой. Для выполнения такой синхронизации в Delphi применяется специальный метод Synchronize, в рамках которого и нужно вызывать процедуры, модифицирующие свойства визуальных компонентов.
Процедура Synchronize использует в качестве параметра те процедуры, в которых происходит модификация свойств визуальных компонентов, и блокирует одновременный доступ к компоненту нескольких потоков. Вот какой пример, в частности, содержится в модуле, сгенерированном Мастером создания потока:
{Важно: Методы и свойства объектов в визуальных компонентах могут вызываться
только в методе Synchronize, например:}
procedure MyThread.UpdateCaption;
begin
Form1.Caption:= 'Updated in a thread';
end;
procedure MyThread.Execute;
begin
Synchronize(UpdateCaption);
end;
В данном случае поток используется для изменения заголовка Формы. Изменение заголовка происходит в процедуре UpdateCaption. Казалось бы, для изменения заголовка эту процедуру достаточно вызвать в основной процедуре потока, Execute. Однако, если несколько таких потоков в программе одновременно попытаются изменить заголовок Формы, то это может привести к непредсказуемым последствиям. Для исключения этого процедура UpdateCaption вызывается в процедуре Execute как параметр метода Synchronize.
Нужно знать, что метод Synchronize выполняется в главном потоке приложения. Поэтому, работая с несколькими потоками в приложении и применяя метод Synchronize, нужно учитывать, что:
Как пример рассмотрим всё ту же модификацию заголовка Формы. Пусть в одном из потоков происходит работа с большим массивом, и требуется отображать какой объём массива уже обработан. Для этого организуем поток, который будет выполнять эту работу. Будем выводить в заголовок Формы индекс элемента, с которым обрабатывающий поток работает в данный момент. Делать это будем с периодичностью 10 раз в секунду. Сначала сделаем так:
procedure TMyThread.UpdateCaption;
begin
while True do
begin
Form1.Caption:=IntToStr(Cap);
sleep(100);
end;
end;
procedure TMyThread.Execute;
begin
Synchronize(UpdateCaption);
end;
Видим, что происходит именно то, о чём написано выше. Так как весь код потока, и модификация заголовка Формы, и цикл ожидания, выполняется в методе Synchronize, а значит в главном потоке, то приложение будет выглядеть зависшим, и его даже будет невозможно корректно завершить.
Теперь попробуем вывести цикл за пределы Synchronize:
procedure TMyThread.UpdateCaption;
begin
Form1.Caption:=IntToStr(Cap);
end;
procedure TMyThread.Execute;
begin
while True do
begin
Synchronize(UpdateCaption);
sleep(100);
end;
end;
Это правильный вариант. С помощью метода Synchronize выполняется только непосредственная модификация Заголовка Формы, а цикл ожидания выполняется в потоке, и не мешает главному потоку.
Некоторым объектам VCL процедура Synchronize не требуется, так как они всё же умеют корректно работать с потоками, либо нуждаются в других методах синхронизации. Так, корректно работают с потоками
Кроме визуальных компонентов, также не умеют работать с потоками списки TList. Поэтому в потоках следует использовать объекты TThreadList, которые имеют методы блокировки и разблокировки LockList и UnLockList.
Урок 16.
Дата добавления: 2015-12-08; просмотров: 50 | Нарушение авторских прав