QWorker新增了和XE7的System.Threading单元的For循环并发支持,方法是TQForJobs.For(xxx)。XE7中的For循环在等待作业完成前,如果在主线程中阻塞消息循环处理,这样子,会造成界面的假死。QWorker的For循环解决了这一问题,AMsgWait参数设置为True时,如果当前等待处于主线程中时,会使用消息循环等待;如果不处于主线程,则死等。同时QWorker的For语法支持2007-XE7的所有版本的Delphi,而不仅仅局限于XE7。
先看下QWorkerk中For的函数语法:
class function TQForJobs.&For(const AStartIndex, AStopIndex: NativeInt; AWorkerProc: TQForJobProc; AMsgWait: Boolean; AData: Pointer; AFreeType: TQJobDataFreeType): TWaitResult; class function TQForJobs.&For(const AStartIndex, AStopIndex: NativeInt; AWorkerProc: TQForJobProcA; AMsgWait: Boolean; AData: Pointer; AFreeType: TQJobDataFreeType): TWaitResult; class function TQForJobs.&For(const AStartIndex, AStopIndex: NativeInt; AWorkerProc: TQForJobProcG; AMsgWait: Boolean; AData: Pointer; AFreeType: TQJobDataFreeType): TWaitResult;
【参数说明】
AStartIndex:循环起始值
AStopIndex:循环结束值
AWorkerProc:作业处理过程,有三种重载,分别对应类成员函数、匿名函数和全局函数版本。
AMsgWait:是否在等待时允许消息循环,如果为True,则主线程不会被阻塞,消息能够正常处理,程序自己处理必要的阻塞,否则,主线程被阻塞。
AData:作业附加数据,被当做作业的Data成员传递给作业处理函数。
AFreeType:作业附加数据类型,用于决定是否自动释放作业的附加数据,默认由用户负责释放。
【返回值】
返回循环结果,如果成功从AStartIndex循环到AStopIndex,则返回wrSignaled,如果被中途取消(调用Break,或者程序退出),则返回wrAbandoned。
【注意】
AStopIndex应该大于等于AStartIndex,否则循环过程将不会被执行。不象普通的for语句有downto来逆序,TQForJobs.For函数不支持逆序。
【备注】
我们看下For作业过程与普通的作业过程的不同:
TQForJobProc = procedure(ALoopMgr: TQForJobs; AJob: PQJob; AIndex: NativeInt) of object; TQForJobProcG = procedure(ALoopMgr: TQForJobs; AJob: PQJob;AIndex: NativeInt); TQForJobProcA = reference to procedure(ALoopMgr: TQForJobs; AJob: PQJob;AIndex: NativeInt);
与普通的作业过程相比,For循环作业过程多了两个参数:
(1)、ALoopMgr参数是循环作业的控制对象,它提供了一个BreakIt方法用于中断循环的执行;
(2)、AIndex参数指明了当前循环的索引值,表明它是第几个循环。
至于AJob参数,其含义与普通的作业没有任何区别。
【示例】
下面的例子是匿名函数版本:
var ARuns:NativeInt; T,T1:Cardinal; I: Integer; begin ARuns:=0; T:=GetTickCount; TQForJobs.For(0,999999, procedure (AMgr: TQForJobs; AJob: PQJob; AIndex: NativeInt) begin AtomicIncrement(ARuns); end ,False,nil); T:=GetTickCount-T; ShowMessage(IntToStr(T)+'ms'); end;
下面的例子是类成员函数版本:
procedure TForm1.DoForJobProc(AMgr: TQForJobs; AJob: PQJob; AIndex: NativeInt); begin InterlockedIncrement(PInteger(AJob.Data)^); end; procedure TForm1.Button1Click(Sender:TObject); var ARuns:NativeInt; T,T1:Cardinal; I: Integer; begin ARuns:=0; T:=GetTickCount; TQForJobs.For(0,999999,DoForJobProc,False,@ARuns); T:=GetTickCount-T; ShowMessage(IntToStr(T)+'ms'); end;
全局函数版本与类成员函数版本一致,只是作业过程变成全局函数而已,就不啰嗦了。