Потоки в Delphi

Организация многопоточной работы в Delphi




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


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

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














декоративные заборы ограждения

работа в москве в модельном агентстве

   Потоки в Delphi выполняют функцию имитации псевдопараллельной работы приложения. Как известно, для организации многозадачности операционная система выделяет каждому приложению, выполняющемуся в настоящий момент, определённые кванты времени, длина и количество которых определяется его приоритетом. Поэтому объём работы, который приложение может выполнить, определяется тем, сколько таких квантов оно сможет получить в единицу времени. Для операционной системы каждый поток является самостоятельной задачей, которой выделяются кванты времени на общих основаниях. Поэтому приложение Delphi, умеющее создать несколько потоков, получит больше времени операционной системы, и соответственно сможет выполнить больший объём работы.

   Создать дополнительный поток в Delphi поможет объект TThread. Ввести объект TThread в программу можно двумя способами:

  1. с помощью Мастера;
  2. вручную.
   1. Мастер создания дополнительного потока в Delphi создаёт отдельный модуль, в рамках которого выполняется поток. Выполним:

   File -> New -> Other...

В появившейся табличке выбора найдём TThread Object. Появится окошко, в верхнюю строку которого (Class Name) введём имя нашего будущего потока: MyThread. В результате будет создан модуль, содержащий заготовку кода, реализующего дополнительный поток Delphi:
unit Unit2; // Имя модуля, содержащего поток. При сохранении его можно изменить.

interface

uses
  Classes;

type
  MyThread = class(TThread) //MyThread - заданное нами имя потока.
  private
    { Private declarations }
  protected
    procedure Execute; override;
  end;

implementation

{ Important: Methods and properties of objects in visual components can only be
  used in a method called using Synchronize, for example,

      Synchronize(UpdateCaption);

  and UpdateCaption could look like,

    procedure MyThread.UpdateCaption;
    begin
      Form1.Caption := 'Updated in a thread';
    end; }

{ MyThread }


procedure MyThread.Execute;
begin
  { Place thread code here }
end;

end.

   2. В первом способе класс MyThread был создан мастером в дополнительном модуле. Второй способ состоит в том, что мы сами создаём такой класс в рамках одного из уже существующих модулей программы, например, в модуле Unit1:

unit Unit1; //Обычный модуль в котором описывается основная программа

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

//Здесь необходимо описать класс TMyThread:
  TMyThread = class(TThread)
    private
    { Private declarations }
  protected
    procedure Execute; override;
  end;

var
  Form1: TForm1;
//Нужно ввести переменную класса TMyThread
  MyThread: TMyThread;

implementation

{$R *.dfm}

//Нужно создать процедуру Execute, уже описанную в классе TMyThread
procedure TMyThread.Execute;
begin
Здесь описывается код, который будет выполняться в потоке
end;


   Если поток создаётся мастером, т.е. в другом модуле, то не забудьте в основном модуле описать переменную - экземпляр потока, как указано выше. Также, поскольку класс потока описан в другом модуле, имя этого модуля необходимо добавить в секцию uses. Теперь можно запускать поток, даже если в его процедуре Execute нет ни единого оператора.

//Запускать поток будем нажатием на кнопку:
procedure TForm1.Button1Click(Sender: TObject);
begin
//Вначале нужно создать экземпляр потока:
  MyThread:=TMyThread.Create(False);
//Параметр False запускает поток сразу после создания, True - запуск впоследствии , методом Resume
//Далее можно указать параметры потока, например приоритет:
  MyThread.Priority:=tpNormal;
//Можно указать что после завершения кода поток завершится автоматически:
  MyThread.FreeOnTerminate:=true;
end;

end.

   Ну вот, даже этот минимальный код позволяет поэкспериментировать с потоками и посмотреть, что они создаются в системе, работают, уничтожаются. Например, измените условие завершения потока:

  MyThread.FreeOnTerminate:=false; //Поток не будет уничтожен после завершения работы

Теперь в Диспетчере Задач Windows можно наблюдать, что при каждом нажатии на кнопку Button1 в нашем приложении количество потоков в проекте Project1 увеличивается.

А теперь поместите в процедуру Execute такой оператор:

   MyThread.Terminate;

Метод Terminate уничтожает данный экземпляр потока. Теперь при нажати кнопки в приложении количество потоков всё равно остаётся равным 1 (это главный поток приложения), так как сразу после создания новый поток уничтожается методом Terminate, и мы просто не успеваем заметить краткий миг его существания. Тем не менее, это означает, что код потока в процедуре Execute выполняется!

Ещё пример. Если в основной программе попробовать выполнить такой цикл:

   while True do;

то приложение зависнет. А теперь поместите его в процедуру Execute. При нажатии на кнопку наш бесконечный цикл будет непрерывно выполняться в потоке, однако и приложение как целое не зависнет.

   При работе с потоками необходимо учитывать приоритет создаваемых потоков. Так, если в предыдущем примере запустить не один поток, а два или больше, то компьютер станет очень заметно "тормозить". Это происходит потому что приоритет по умолчанию новых потоков - нормальный. Можно уменьшить его, задав

MyThread.Priority:=tpLower;

Этого достаточно, чтобы компьютер чувствовал себя более свободно. Вот таблица приоритетов:

Приоритет Описание
tpIdle Низший приоритет. Поток получает время только тогда, когда операционая система находится в состоянии простоя.
tpLowest Приоритет на два пункта ниже нормального
tpLower Приоритет на один пункт ниже нормального
tpNormal Нормальный приоритет
tpHigher Приоритет на один пункт выше нормального
tpHighest Приоритет на два пункта выше нормального
tpTimeCritical Максимальный приоритет. Приоритет на уровне функций ядра операционной системы.


Вот вам готовый проект работы c потоками, для экспериментов.

   В продолжение темы нужно рассмотреть

Особености взаимодействия потоков с объектами VCL

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


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

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

Вопросы и комментарии (21)

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

Имя  

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