QWorker 技巧 – 多步作业中参数重复投寄

QWorker  中作业投递时,如果需要传递一个参数,但我们如果设置jdfFreeAsObject,那么显然单次作业完成后,相关的参数就会被释放,无法传递到下一个作业。那么这个时候,我们该怎么做呢?

本文提供了一个简单的办法来解决这一问题:用 QString 单元为您提供的 TQPtr 做智能指针封装,然后作业时使用 jdfFreeAsInterface 让 QWorker 采用接口的方式来管理附加的数据。

我们先看一下声明:

IQPtr = interface(IInterface)
    function Get: Pointer;
  end;
  TQPtrFreeEvent=procedure (AData:Pointer) of object;
  TQPtrFreeEventG=procedure (AData:Pointer);
  {$IFDEF UNICODE}
  TQPtrFreeEventA=reference to procedure (AData:Pointer);
  {$ENDIF}
  TQPtr = class(TInterfacedObject, IQPtr)
  private
    FObject: Pointer;
    FOnFree:TQPtrFreeEvent;
    {$IFDEF UNICODE}
    FOnFreeA:TQPtrFreeEventA;
    {$ENDIF}
  public
    constructor Create(AObject: Pointer); overload;
    destructor Destroy; override;
    class function Bind(AObject: TObject): IQPtr;overload;
    class function Bind(AData:Pointer;AOnFree:TQPtrFreeEvent):IQPtr;overload;
    class function Bind(AData:Pointer;AOnFree:TQPtrFreeEventG):IQPtr;overload;
    {$IFDEF UNICODE}
    class function Bind(AData:Pointer;AOnFree:TQPtrFreeEventA):IQPtr;overload;
    {$ENDIF}
    function Get: Pointer;
  end;

我们会用到其中的 TQPtr.Bind 函数和 IQPtr 的 Get 接口:

(1)Bind 函数用于将对象或其它类型的指针通过接口的方式进行管理,它有四种重载,如果是对象,不需要指定释放方法,如果是其它的如记录类型,就需要自己指定内存释放函数,后面三个分别对应类成员、全局函数和匿名函数版本,不进行赘述。

(2)Get 函数用于获取到咱们管理的原始的指针。

下面我们提供一个具体的例子来看一下它的用法:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs,QString,QWorker, Vcl.StdCtrls;

type
  TMyObject=class
  public
    Text:String;
    destructor Destroy;override;
  end;
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    procedure DoStep1(AJob:PQJob);
    procedure DoStep2(AJob:PQJob);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
Workers.Post(DoStep1,Pointer(TQPtr.Bind(TMyObject.Create)),False,jdfFreeAsInterface);
end;

procedure TForm1.DoStep1(AJob: PQJob);
var
  AObj:TMyObject;
begin
AObj:=IQPtr(AJob.Data).Get;
AObj.Text:='Hello,world from DoStep1';
Workers.Post(DoStep2,AJob.Data,True,jdfFreeAsInterface);
end;

procedure TForm1.DoStep2(AJob: PQJob);
var
  AObj:TMyObject;
begin
AObj:=IQPtr(AJob.Data).Get;
ShowMessage(AObj.Text);
end;

{ TMyObject }

destructor TMyObject.Destroy;
begin
  OutputDebugString('Object Free');
  inherited;
end;

end.

上面的这段代码我们投寄了一个两步作业,第一步作业设置了 TMyObject 的一个实例的 Text 值,而第二步作业则将其用 ShowMessage 显示出来,我们没有自己释放 TMyObject 实例,但我们执行上面的代码,我们可以看到结果,截个图看下:

FreeAsInterface

InfFree

可以看到,在后续步骤中,参数被安全的访问,而TMyObject对象的实例被自动释放了。

韦小宝的原话:大功告成,亲一个~~~

 

 

分享到: