Модели потоков. Класс TThread

   
На этом шаге мы рассмотрим особенности использования этого класса.

   
В Delphi вычисления в потоках реализуются при помощи абстрактного класса TThread, для чего необходимо создать класс-потомок и при помощи директивы override перекрыть абстрактный метод Execute:

type
  TMyThread = class(TThread) 
  protected
    procedure Execute: override; 
  end;
  .   .   .
  procedure TMyThread.Execute; 
  begin
  // Программный код
  end;

   
Код, который реализуется в методе Execute, выполняется в отдельном потоке. Для его запуска просто необходимо создать экземпляр класса TMyThread:

  ТМуThread.Create(False);

   
СОМ-объекты самостоятельно, без использования класса TThread, поддерживают вычисления в потоках. Однако этот класс полезно рассмотреть с точки зрения анализа сложностей, возникающих при создании
многопоточных приложений.

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

  • Suspend - переводит работающий поток в состояние ожидания;
  • Resume - переводит ожидающий ноток в рабочее состояние.

   
Конструктор класса TThread принимает в качестве параметра логическую переменную CreateSuspended. Если ее значение равно True, то конструктор полностью отрабатывается, но поток находится в
состоянии ожидания. Для его запуска требуется вызов метода Resume. При значении этого параметра, равном False, код в методе Execute начинает выполняться немедленно после отработки конструктора.
Нельзя вызывать конструктор класса-потомка TThread с параметром False, если происходит инициализация свойств в классе:

type
  TMyThread = class(TThread) 
  protected
    procedure Execute: override; 
  public
    FR: Single; 
  end;
  .   .   .   .
  procedure TMyThread.Execute; 
  var
    R: Single; 
  begin
  .   .   .   .
    R := Sqrt(FR - 1); 
  .   .   .   .
  end;
  .   .   .   .
  procedure TForm1.ButtonlClick(Sender:TObject); 
  begin
    with TMyThread.Create(False) do FR := 5; 
  end;

   
На первый взгляд этот код не содержит ошибки: создается отдельный ноток, присваивается начальное значение переменной FR и продолжается расчет с использованием этого значения. Однако поскольку после отработки
конструктора код, реализованный в методе Execute, выполняется в отдельном потоке, то оператор R := sqrt(FR-1) из метода ТМуThread.Execute может быть выполнен раньше оператора FR := 5 из
метода TForm1.ButtonlClick. Соответственно, значение переменной FR после отработки конструктора равно 0, и в такой ситуации будет происходить исключение ЕInvalidOp (попытка извлечь квадратный
корень из -1). Поиск и устранение такого типа ошибки усложняются тем, что, вообще говоря, эта ошибка непостоянна и в некоторых случаях может проявляться очень редко. Для устранения указанной ошибки код в методе
Button1Click следует переписать:

  procedure TForm1.ButtonlClick(Sender:TObject); 
  begin
    with TMyThread.Create(True) do begin FR := 5; 
    Resume; 
    end; 
  end;

   
В приведенном фрагменте кода первоначально создается экземпляр класса TMyThread в режиме ожидания, затем присваиваются начальные значения всем свойствам и переменным класса и только после этого вызывается
метод Resume, который начинает выполнение кода. Это единственно правильный способ инициализации данных: поток не запускается до тех пор, пока не заданы значения всех переменных.

   
На следующем шаге мы закончим изучение этого вопроса.



Вы можете оставить комментарий, или Трекбэк с вашего сайта.

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