Есть ли способ немедленно завершить TTask?

#delphi #asynchronous #jpeg

#delphi #асинхронный #jpeg

Вопрос:

TTask все еще выполняется даже после вызова Cancel .

У меня есть сетка, которую я прокручиваю стрелками клавиатуры, при каждом изменении строки я уничтожаю старое TAsyncImage (если таковое имеется) и создаю новое TAsyncImages для новой строки и загружаю изображения. Если я прокручиваю достаточно быстро, оказывается, что старые TTasks из уничтоженных TAsyncImages все еще выполняются и каким-то образом изменяют вновь созданные TAsyncImages.

 type
  TAsyncImage = class(TImage)
  private
    FTask: ITask;
    FOnFinish: TNotifyEvent;
    FOnLoaded: TNotifyEvent;
    procedure SetOnFinish(const Value: TNotifyEvent);
    procedure SetOnLoaded(const Value: TNotifyEvent);
  public
    destructor Destroy; override;
    property Async: Boolean read FAsync write FAsync;
    property OnThumbLoaded: TNotifyEvent read FOnLoaded write SetOnLoaded;
    property OnFinish: TNotifyEvent read FOnFinish write SetOnFinish;
  end;

implementation

{ TAsyncImage }
destructor TAsyncImage.Destroy;
begin
  if Assigned(FTask) and (FTask.Status = TTaskStatus.Running) then
  begin
    FTask.Cancel;
    CheckSynchronize;
  end;

  FPicture.Free;
  inherited Destroy;
end;

procedure TAsyncImage.LoadFromJPEG(AFileName: string; Scale: TJPEGScale);
var
  J: TJPEGImage;
begin
  if FAsync then
  begin
    FTask := TTask.Run(
      procedure
      var
        B: TBitmap;
        J: TJPEGImage;
      begin
        J := TJPEGImage.Create;
        B := TBitmap.Create;
        try
          J.LoadFromFile(AFileName);
          TThread.Synchronize(nil,
            procedure
            begin
              if Assigned(FOnLoaded) then
                FOnLoaded(Self);
            end
          );


          J.Scale := jsEighth;
          B.Assign(J);

          if TTask.CurrentTask.Status = TTaskStatus.Canceled then
            Exit;

          TThread.Synchronize(nil,
            procedure
            begin
              if Assigned(Picture) then
                Picture.Assign(B);
            end);

          if TTask.CurrentTask.Status = TTaskStatus.Canceled then
            Exit;

          if Scale <> jsEighth then
          begin
            J.Scale := Scale;
            B.Assign(J);
            TThread.Synchronize(nil,
              procedure
              begin
                if Assigned(Picture) then
                  Picture.Assign(B);

                if Assigned(FOnFinish) then
                  FOnFinish(Self);
              end);
          end;



        finally
          J.Free;
          B.Free;
        end;
      end
    );
  end
  else
  begin
    J := TJPEGImage.Create;
    J.LoadFromFile(AFileName);
    if Assigned(FOnFinish) then
      FOnFinish(Self);
    J.Scale := Scale;
    Picture.Assign(J);
    J.Free;
  end;
end;

  

Или, если есть какое-либо лучшее решение для асинхронной загрузки изображений.

Комментарии:

1. 2 идеи. 1 используйте TThread.CreateAnonymousThread вместо TTask.Run . 2. используйте флаг, который виден потоку, для завершения потока.

2. Предполагаемое решение нежизнеспособно. Принудительное завершение не является решением. Ищите другое решение.