Перейти к содержанию
Fire Monkey от А до Я
  • 0

Использование ITask


Maximus

Вопрос

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

Для теста создал простенький класс

unit ThreadTask;

interface

uses
  System.SysUtils, System.Threading, System.Classes;

type
  TOnCollback = procedure(ID: Integer) of object;

  TThreadTask = class
    private
      Task: ITask;

      procedure Execute;
      procedure Print;
      procedure Close;
    public
      OnDestroy: TOnCollback;
      OnPrint: TOnCollback;

      Destructor Destroy; override;

      procedure Start;
      procedure Stop;
  end;

implementation

{ TThreadTask }

procedure TThreadTask.Close;
begin
  if Assigned(OnDestroy) then
    OnDestroy(Task.Id);
end;

destructor TThreadTask.Destroy;
begin
  Stop;
  TThread.Synchronize(TThread.CurrentThread, Close);

  inherited;
end;

procedure TThreadTask.Execute;
begin
  TThread.Sleep(3000);
  TThread.Synchronize(TThread.CurrentThread, Print);
  TThread.Sleep(3000);
  TThread.Synchronize(TThread.CurrentThread, Print);

  Free;
end;

procedure TThreadTask.Print;
begin
  if Assigned(OnPrint) then
    OnPrint(Task.Id);
end;

procedure TThreadTask.Start;
begin
  Task := TTask.Run(Execute);
end;

procedure TThreadTask.Stop;
begin
  if Assigned(Task) and (Task.Status = TTaskStatus.Running) then
    Task.Cancel;
end;

end.

 

Класс включает в себя интерфейс ITask и после создания и вызова метода Start должен в потоке выполнять какие-то вычисления, в данном случае это просто задержка и вызов коллбека. После отработки класс вызывает коллбек для уведомления о завершении работы и самостоятельно разрушается.

Код использования класса:

unit Unit1;

interface

uses
  ..., ThreadTask;

type
  TForm1 = class(TForm)
    Memo: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    ThreadTask: TThreadTask;

    procedure TreadDestroy(ID: Integer);
    procedure TreadPrint(ID: Integer);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.Button1Click(Sender: TObject);
begin
  if Assigned(ThreadTask) then
    FreeAndNil(ThreadTask);

  ThreadTask := TThreadTask.Create;
  ThreadTask.OnDestroy := TreadDestroy;
  ThreadTask.OnPrint := TreadPrint;
  ThreadTask.Start;
end;

procedure TForm1.TreadDestroy(ID: Integer);
begin
  Memo.Lines.Add(Format('ThreadTask №%d уничтожен', [ID]));
  ThreadTask := nil;
end;

procedure TForm1.TreadPrint(ID: Integer);
begin
  Memo.Lines.Add(Format('Я Task №%d', [ID]));
end;

end.

По нажатию на кнопку проверяем не существует ли предыдущий экземпляр класса, если существует уничтожаем его, создаём новый и запускаем его. Приходящие сообщения от класса выводим в Memo.

Если запустить и дождаться полной отработки потоком, то всё ожидаемо, в Memo видим:

Я Task №1
Я Task №1
ThreadTask №1 уничтожен

Однако если не дождавшись окончания работы первого потока ещё раз нажать на кнопку, то вывод получается совсем не тем, что ожидалось:

ThreadTask №1 уничтожен
Я Task №2
Я Task №2
Я Task №2
ThreadTask №2 уничтожен

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

procedure TForm1.Button1Click(Sender: TObject);
begin
  if Assigned(ThreadTask) then
    begin
      ThreadTask.OnDestroy := nil;
      ThreadTask.OnPrint := nil;
      FreeAndNil(ThreadTask);
    end;

  ThreadTask := TThreadTask.Create;
  ThreadTask.OnDestroy := TreadDestroy;
  ThreadTask.OnPrint := TreadPrint;
  ThreadTask.Start;
end;

Но это не даёт нужного результата, вывод в Memo практически аналогичен предыдущему:

Я Task №1
Я Task №1
Я Task №1
ThreadTask №1 уничтожен

Может быть Task нельзя так использовать или я что-то делаю не так?

Изменено пользователем Maximus
Ссылка на комментарий

Рекомендуемые сообщения

  • 0

В общем оказалось, что и ITask можно использовать, главное следовать тем же правилам что и при работе с TThread. Если ставим саморазрушение в объект, то извне его разрушать нельзя. А если это всё же необходимо, то придётся убрать саморазрушение после отработки и подождать завершения задачи, в которой можно поставить проверки Task.Status = Canceled для преждевременной остановки задачи.

Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...