Потоки в Delphi

Использование метода Synchronize при работе с потоками




Уроки Delphi
  1.  Первая программа
  2.  Использование компонентов
  3.  События Delphi
  4.  Типы данных Delphi
  5.  Создание своих типов данных
  6.  Выражения и операторы
  7.  Работа с файлами в Delphi
  8.  Дополнительные формы
  9.  Подпрограммы в Delphi
  10. Исключительные ситуации
  11. Взаимодействие приложения с пользователем
  12. Указатели в Delphi
  13. Обзор компонентов
  14. Работа со строками
  15. Создание интерфейса
  16. Графика в Delphi
  17. Многопоточность в Delphi
  18. Динамическое создание
        компонентов
Поиск по сайту




 Это важно:
   Метод Application.ProcessMessages;

 Это полезно:
   Параметр Sender в обработчиках событий;










Бояться не надо



   При использовании в приложении нескольких потоков необходимо гарантировать, что в данный момент только один из потоков может иметь доступ к свойствам и методам объекта 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, нужно учитывать, что:

  • во-первых, частый вызов Synchronize тормозит выполнение приложения;
  • во-вторых, если практически все процедуры выполняющегося потока выполняются с использованием метода Synchronize, то смысла в создании такого потока нет - всё равно его работа пройдёт в главном потоке.
   Как пример рассмотрим всё ту же модификацию заголовка Формы. Пусть в одном из потоков происходит работа с большим массивом, и требуется отображать какой объём массива уже обработан. Для этого организуем поток, который будет выполнять эту работу. Будем выводить в заголовок Формы индекс элемента, с которым обрабатывающий поток работает в данный момент. Делать это будем с периодичностью 10 раз в секунду. Сначала сделаем так:

procedure TMyThread.UpdateCaption;
begin
while True do
  begin
    Form1.Caption:=IntToStr(I);//I - глобальная переменная основной программы, индекс массива
    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 не требуется, так как они всё же умеют корректно работать с потоками, либо нуждаются в других методах синхронизации. Так, корректно работают с потоками
  • компоненты доступа к базам данных (с использованием компонентов класса TSession). Исключение составляют базы данных Microsoft Access;
  • классы, которые работают непосредственно с графикой. Это TFont, TPen, TBrush, TBitmap, TMetafile и TIcon. Канву объектов этих классов (Canvas) можно использовать не применяя метод Synchronize. Это делается с помощью блокировки канвы. То есть, поток, использующий в данный момент канву, предварительно блокирует канву методом Lock, препятствующим другим потокам работать с канвой, и разблокирует затем методом UnLock.
   Кроме визуальных компонентов, также не умеют работать с потоками списки TList. Поэтому в потоках следует использовать объекты TThreadList, которые имеют методы блокировки и разблокировки LockList и UnLockList.


Графика в Delphi           В начало урока          Следующий урок  

Уроки Delphi начинающим



Вопросы и комментарии (1)      Решение задач в Delphi

Оставить комментарий:

Имя  

Текст комментария