Delphi World - Особенности разработки потоков
Delphi World - это проект, являющийся сборником статей и малодокументированных возможностей  по программированию в среде Delphi. Здесь вы найдёте работы по следующим категориям: delphi, delfi, borland, bds, дельфи, делфи, дэльфи, дэлфи, programming, example, программирование, исходные коды, code, исходники, source, sources, сорцы, сорсы, soft, programs, программы, and, how, delphiworld, базы данных, графика, игры, интернет, сети, компоненты, классы, мультимедиа, ос, железо, программа, интерфейс, рабочий стол, синтаксис, технологии, файловая система...
Особенности разработки потоков

Современные операционные системы Windows 32 обеспечивают не только многозадачность, т. е. возможность параллельной работы нескольких программ, но и многопоточность, когда в рамках одной программы организуется несколько параллельно выполняемых фрагментов (потоков), каждый из которых конкурирует с другими потоками за наиболее важный ресурс - время центрального процессора. В многопоточном режиме время ЦП выделяется для каждого процесса небольшими порциями (квантами), по истечении этого времени управление передается другому потоку и т. д. до тех пор, пока потоки не закончат свою работу. В любой работающей программе организуется как минимум один поток для команд программы. С помощью объектов класса TThread программа может создать дополнительные потоки для проведения некоторой фоновой работы (например, текстовый процессор Word создает дополнительные потоки для проверки правильности орфографии, разбивки на страницы, печати документа и т. п.).

Для создания дополнительного потока в программах Delphi предназначен специальный модуль потока в репозитории он обозначен пиктограммой Thread Obiecll). При выборе этого модуля Delphi запрашивает имя класса, который будет дочерним для основополагающего класса TThread. Необходимость наследования связана с тем, что класс TThread содержит абстрактный метод Execute, который, собственно, и должен исполняться в рамках нового потока и который, следовательно, обязан перекрываться в потомках.

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

Например (с соответствующим переводом):

unit Unit1;

interface
uses
  Classes;

type
  MyThread = class(TThread)
  private
    { Private declarations }
  protected
    procedure Execute; override;
  end;

implementation

{ Важно: Методы и свойства объектов из библиотеки визуальных компонентов
могут использоваться только в рамках вызова метода Synchronize, например:

Synchronize(UpdateCaption);
где метод UpdateCaption должен быть подобен такому

procedure MyThread.UpdateCaption;
begin
  Formi.Caption := 'Новый текст метки';
end; }

(MyThread}

procedure MyThread.Execute;
begin
  { Пожалуйста, поместите код потока в этом месте }
end;

end.

Программирование потока ничем не отличается от программирования обычной программы за одним важным исключением: поток не должен использовать методы и свойства визуальных компонен тов, которые приводят к изменению внешнего вида программа Точнее, он может это делать только при обращении к специальному методу synchronize, с помощью которого осуществляется синхронизация исполнения главного потока программы с дополнительным потоком.

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

Для ее создания сначала на пустую форму поместите панель TPpanel, очистите ее свойство caption и поместите в Align значение аlRight - эта панель предназначена для размещения редактора TSpinEdit, кнопки TButton и индикатора TGauge и всегда должна располагаться в правой части окна программы. Поместите на панель перечисленные компоненты так, как это показано на рисунке (компоненты TSpinEdit и TGuage находятся на странице samples палитры компонентов).

Установите в свойство SpinEditl.Value 3начение 2, присвойте свойству Gaugel. Kind значение gkPie, Gaugel. BorderStyle-bsNone и Button1.Caption — 'Квадрат'.

На свободное место формы положите компонент TMemo и установите для него в свойство Align значение alСlient, а свойство Name- 'mmOutput'.

Теперь создадим обработчик события Button1.Click: при нажатии на кнопку вначале содержимое редактора SpinEdit1 возводится в квадрат до тех пор, пока отображаемое в нем значение не слишком большим (больше 10 +1233 ). В этот момент надпись на кнопке меняется на “корень”, а нажатие на нее вычисляет корень квадратный ИЗ величины SpinEdit1.

Дважды щелкните по кнопке Button1и напишите такой код:

procedure TForm1.Button1Click(Sender: TObject);
begin
  if Tag = 0 then
  begin
    SpinEditl.Text := Float - ToStr(sqr(StrToPloat(SpinEditl.Text)));
    if StrToFloat(SpinEditl.Text) > 1 el233 then
    begin
      Tag := 1;
      Buttoni.Caption := 'Корень'
    end
  end
  else
  begin
    SpinEditl.Text := FloatToStr(sqrt(StrToFloat(SpinEditl.Text)));
    if StrToFloat(SpinEditl.Text) < 2 then
    begin
      SpinEditl.Value := 2;
      Tag := 0;
      Button1.Caption := 'Квадрат'
    end
  end
end;

Таким образом, главный код программы связан с извлечением корня или возведением в квадрат величины, записанной в редакторе SpinEditl.

Теперь создадим модуль потока, в методе Execute которого будем непрерывно формировать по 100 строк в редакторе mmOutput и показывать процент заполнения редактора с помощью индикатора Gaugel.

Выберите пиктограмму модуля потока в окне репозитория Delphi и дайте наследнику класса Thread имя ThreadDemo. Окончательный текст модуля потока представлен ниже.

unit Unit2;

interface
uses
  Classes;

type
  ThreadDemo = class(TThread)
  private
    { Private declarations }
  protected
    S: string;
    N: Integer;
    procedure UpdateMemo;
    procedure UpdateGauge;
    procedure Execute; override;
  end;

var
  TDemo: ThreadDemo;

implementation

uses Uniti, SysUtils;

{ Important: Methods and properties of objects in VCL can only re used.
in a method called using Synchronize, for example,

Synchronize(UpdateCaption);
and UpdateCaption could look like,

procedure ThreadDemo.UpdateCaption;
begin
  Formi.Caption := 'Updated in a thread';
end;

ThreadDemo}

procedure ThreadDemo.Execute;
var
  j, k: Integer;
begin
  repeat
    S := '';
    Synchronize(UpdateMemo);
    for k := 0 to 99 do
    begin N := k;
      S: = ' ';
      for j := 1 to 20 do
        S := S + FormatFloat('00', k), Synchronize(UpdateMemo);
      Synchronize(UpdateGauge)
    end;
  until False
end;

procedure ThreadDemo.UpdateMemo;
begin
  with .Form1.mmOutput.Lines do
    if S = ' ' then
      Clear else
      Add(S)
end;

procedure ThreadDemo.UpdateGauge;
begin
  Form1.Gaugel.Progress := N
end;

end.

Если вы запустите таким способом подготовленную программу, то ничего не произойдет - ведь мы еще не запустили поток. Чтобы сделать это, добавьте в модуле Unit1 главной формы ссылку uses Unit1, раскройте в окне Инспектора объектов список компонентов, выберите компонент Form1 и на его странице Event дважды щелкните по свойству onActivate, чтобы создать такой обработчик этого события:

procedure TForm1.FormActivate(Sender: TObject);
begin
  TDemo := ThreadDemo.Create(False),
end;

Вот так просто запускается дополнительный поток - мы инициируем объект TDemo, передавая в его Консруктор ThreadDemo.Create

единственный параметр False (этот параметр показывает, должен ли вновь созданный поток “спать” - True или он обязан немедленно начать работу - False). Программа в любой момент может приостановить работу потока, присвоив его свойству suspended значение True, и продолжить его выполнение, присвоив этому свойству значение False. Обратите внимание - метод Execute потока вынесен в секцию protected и поэтому недоступен из основного модуля. Выполнение этого метода начинается автоматически, как только свойство suspended примет значение False.

Для обращения к свойствам и методам визуальных компонентов формы Form1 предназначен специальный метод потока Synchronize. Единственным параметром обращения к этому методу должно быть имя любой потоковой процедуры без параметров. Внутри такой процедуры разрешается обращаться к методам и свойствам визуальных компонентов. В нашем потоке две такие процедуры - UрdateMemo и updateGuage. В первой строка s добавляется к содержимому редактора mmoutput, во втором - глобальная переменная n присваивается свойству progress индикатора Gauge1. Поскольку эти процедуры не могут иметь параметров, для управления их работой приходится использовать глобальные переменные S и N.

Проект Delphi World © Выпуск 2002 - 2017
Автор проекта: Эксклюзивные курсы программирования