示例-QWorker后台线程与前台通讯演示解析

关于前后台通讯这一点,我在文章 QWorker技巧之作业与主线程之间通讯 中对此进行了一些说明,但一直没有给出单独的示例。因此在群里,许多朋友对QWorker如何和前台线程通讯还是有点犯迷糊。所以,我特意写了一个小演示程序,来演示如何做到这一点。

这个示例在主线程中是要分别更新10个进度条的进度信息,先看一下截图:

ProgressDemo_1

声明下,本示例演示了如何在QWorker中后台作业与界面元素进行交互的基本方法,当然这不是唯一的方法,主要是提供一个参考,更多的方法参考前面提到的文章。
本示例演示了一个三步作业:

  1. 分别填充8个TStringList对象,并显示填充进度。
  2. 合并8个TStringList的结点到第一个TStringList
  3. 在后台线程中遍历合并后的TStringList,来尝试指到特定的字符 A 出现的次数。

本示例用到了以下功能:

  1. 使用TQJobGroup做了一个串行化作业,保证上面的三步按顺序执行。
  2. 使用TQWorkers.For做了并行计算,填充8个TStringList列表。
  3. 使用TQMsgPack来传递进度参数到主线程来更新进度。

好了,现在我们来解析代码:

这一段代码前面初始化进度条位置为0并设置按钮的Enabled属性为False,以避免重复点击。然后先创建了一个TQJobGroup对象和8个TStringList对象,然后依次添加了三项要顺序执行的作业,然后调用Run和MsgWaitFor来等待作业执行完成。注意这里由于我们要与主线程交互,所以一定要用MsgWaitFor而不是WaitFor,以避免阻塞主线程的消息处理。作业执行完成后,当然就是清理的过程和显示查找的结果,恢复状态,咱就略过不表了。

这两个函数用于DoUpdateProgress根据传过来的参数,来更新10个进度条的进度。而NotifyProgress函数则用于触发DoUpdateProgress在主线程中执行。由于需要参数,因此,使用了TQMsgPack来组合这两个参数,当然,你也可以用一个结构,然后用TQJobExtData来管理它。前面也说了,这里只是多个方案之一。

继续看下一个代码:

第一个作业处理函数DoCreateListData使用For并行来调用DoFillListData来并行填充这8个列表。然后添加过程中,每50ms通知一下主线程更新进度信息。

合并列表作业DoMergeListData合并列表内容,并每合并完一个调用NotifyMessage通知一次进度。直接到合完成。这里的FRepeatTimes实际上在Button1Click里初始化更合适,放在这里我只是想提醒大家,多线程编程中,如果你能确定一个变量没有同时读写,那么直接访问它就是安全的。

这两个DoSearchChar函数第一个用于触发For并行检查是否包含字母A的作业执行,而作业的进度是每扫描完10000项时,通知一次进度。当然,由于循环是 0~MergedCount-1 ,所以最后一次的进度更新我放到了Button1里去完成。

好了,现在您可以直接跑下例子,看一下程序的运行效果了。

本示例的源码位于 Demos\Delphi\VCL\QWorkerProgress 目录下,你可以直接编译运行。

分享到: