基于 QWorker 的多线程编程 – 状态跟踪

当我们将一个作业的执行委托给 Workers 这个包工头以后,那么这个作业实际上就处于三种状态之一:

  • 排队中:作业在队列中等待被调度执行
  • 运行中:作业正在执行
  • 已完成:作业已经执行完,此时作业及相关连的数据都已自动被释放

由于已经完成的作业会被释放掉,所以,实际上,我们能得到的状态只有排队中和运行中两种,第三种由于作业已经不存在,我们就无法检测到其状态。

QWorker 提供了两个函数来跟踪作业的状态:PeekJobState 和 EnumJobStates,前者针对的是单个具体的作业,后者针对的是全部作业。在具体了解这两个函数之前,我们先看一下我们能得到的作业状态信息定义:

【Delphi】

【C++ Builder】

在调用 PeekJobState 时,如果找到作业,则 Handle 与传入的作业句柄一致,Proc 指向作业对应的过程句柄,Flags 是作业的标志位,保存的是 JOB_XXX 标志位,可以通过位与的方式来检查各个标志位是否设置,具体标志位定义参考下表:

JOB_RUN_ONCE : 作业只运行一次
JOB_IN_MAINTHREAD : 作业只能在主线程中运行
JOB_MAX_WORKERS : 尽可能多的开启可能的工作者线程来处理作业,暂不支持
JOB_LONGTIME : 作业需要很长的时间才能完成,以便调度程序减少它对其它作业的影响
JOB_SIGNAL_WAKEUP : 作业根据信号需要唤醒
JOB_TERMINATED : 作业不需要继续进行,可以结束了
JOB_GROUPED : 当前作业是作业组的一员
JOB_ANONPROC : 当前作业过程是匿名函数
JOB_FREE_OBJECT : Data关联的是Object,作业完成或清理时释放
JOB_FREE_RECORD : Data关联的是Record,作业完成或清理时释放
JOB_FREE_INTERFACE : Data关联的是Interface,作业完成时调用_Release
JOB_FREE_CUSTOM1 : Data关联的成员由用户指定的方式1释放
JOB_FREE_CUSTOM2 : Data关联的成员由用户指定的方式2释放
JOB_FREE_CUSTOM3 : Data关联的成员由用户指定的方式3释放
JOB_FREE_CUSTOM4 : Data关联的成员由用户指定的方式4释放
JOB_FREE_CUSTOM5 : Data关联的成员由用户指定的方式5释放
JOB_FREE_CUSTOM6 : Data关联的成员由用户指定的方式6释放
JOB_DATA_OWNER : 作业是Data成员的所有者

好了,现在我们来看 PeekJobState 的定义:

【Delphi】

【C++ Builder】

请注意其中的注释中的 Remark 部分说明,PeekJobState 的返回值为安全起见,建议使用 ClearJobState 来释放返回的结果,以使匿名函数的引用计数在移动平台工作正常。

我们看下 ClearJobState 的实现:

可以看到,只是在 FMX 平台它起作业,VCL 中,由于 ProcA 定义为 TQJobProcA 所以会自动释放(FMX 平台 ProcA 的定义为 Pointer,定义为 TQJobProcA 无法编译)。

下面的代码是 PeekJobState 的一个例子:

当然,上面的例子由于用到了 QMapSymbols 单元的函数,所以只能在 Delphi 的 Windows 下程序中运行。

与 PeekJobState 不同,EnumJobStates 是返回一个动态数组来包含所有的作业的状态,声明如下:

【Delphi】

【C++ Builder】

这个和 PeekJobState 很类似,就不再赘述,直接上示例代码:

在这个示例中,限制了下最多显示前1000个字节的内容,否则太长了,用 ShowMessage 显示会造成假死的现象。

分享到:

0 条评论

沙发空缺中,还不快抢~