Synchronize执行过程
Synchronize执行过程及原理
在windows原生应用程序开发中,经常伴随多线程的使用,多线程开发很简单,难点就是在于线程的同步,在Delphi中提供了VC中不具备的一个过程Synchronize,使用起来非常方便,解决了很多VC开发中碰到的常见问题,但是在看了很多Delphi代码后,发现很多人对于Synchronize的理解还是有问题的,不能很好地正确使用Synchronize过程,本文对Synchronize过程的使用提出一些个人的见解,供大家参考。
在VC中使用多线程,由于MFC或VC本身的特点,VC人员在更新窗口界面和工作线程的关系上分的是比较清楚的,但是Delphi里由于VCL提供的方便特性,造成大量人员在工作线程中更新窗口界面,给系统稳定带来潜在的危险,应该说比较严格的方法应该是永远让更新窗口界面的工作仅由主线程完成,工作线程仅仅做后台的一些工作,当工作线程的结果需要反馈到界面上来的时候,应该使用各种同步对象(临界区、互斥量)等来进行同步,然后让主线程更新窗口界面。
这里由于主要讲解Synchronize的使用,使用同步对象更新的方法就不说了,首先说一下在VC中比较接近Synchronize过程的SendMessage函数,其实在Delphi中也可以使用SendMessage来实现线程同步,实现通知主线程更新窗口界面,只是没有Synchronize过程用起来那么方便。
SendMessage函数的工作过程是比较复杂的,有兴趣的朋友可以多查查SendMessage函数及其同多线程的关系,如果在工作线程中调用SendMessage函数,工作线程会挂起,然后等待主线程空闲,主线程空闲开始处理接收到的消息,处理完成把结果返回,工作线程接收到返回结果后继续运行,也就是消息处理函数是在主线程中运行的,而且工作线程会挂起等待SendMessage函数返回即消息处理函数处理完成才会继续往下执行,在VC开发中这种方式也是经常被使用的。
理解了SendMessage函数工作过程,现在来说一下Synchronize过程的工作过程,Synchronize过程是Delphi底层实现的,其工作原理非常类似SendMessage函数,但是使用起来要比SendMessage函数方便易用,Synchronize过程开始时,也是会挂起当前的工作线程(使用的同步对象),然后让主线程执行Synchronize参数中具体的过程proc,工作线程等待proc执行,proc执行结束返回到工作线程,工作线程再继续执行。
总之,如果在TThread的Execute过程中仅仅调用一个Synchronize过程,Synchronize参数中的过程都是在主线程中执行的,等于没有使用多线程。也就是要细化Synchronize参数中的过程proc,仅让proc执行一些更新界面的工作,不能把真正耗时的动作放在proc中,不然使用多线程没有任何意义。
附:Delphi底层中Synchronize过程的实现过程简介
Synchronize过程的核心函数是System.Classes.pas中的过程class procedure TThread.Synchronize(ASyncRec: PSynchronizeRecord; QueueEvent: Boolean = False);这个函数中是通过调用WakeMainThread事件方法调用具体过程proc的,WakeMainThread事件的注册在Vcl.Forms.pas里,应用程序启动时由Application对象进行注册,WakeMainThread工作过程在Vcl.Forms.pas中为procedureTApplication.WakeMainThread(Sender: TObject);
begin
PostMessage(Handle, WM_NULL, 0, 0);
end;
也就是仅仅把WM_NULL消息放入应用程序消息队列中,工作线程调用完WakeMainThread事件方法即PostMessage以后就挂起(通过同步对象)等待proc执行完成信号触发,Vcl.Forms.pas中主线程消息处理函数中会看到如下代码
WM_NULL:
CheckSynchronize;
即在检索消息循环后碰到WM_NULL消息,会执行CheckSynchronize过程,CheckSynchronize过程在System.Classes.pas中function CheckSynchronize(Timeout: Integer= 0): Boolean; 其工作核心就是执行proc过程,并在执行完成后设置proc执行完成信号,工作线程检测到这个信号后会唤醒,并继续执行后续工作。以上过程中从Synchronize调用到PostMessage都是在工作线程中进行的,然后挂起,检索WM_NULL消息执行CheckSynchronize过程和proc过程都是在主线程中完成的,这些工作完成后,工作线程再唤醒继续执行。
以上来自网友http://blog.csdn.net/gogogo/article/details/10139501
个人调试总结:
1.工作线程调用Synchronize唤醒主线程(其实就是通过回调到主线程WakeMainThread接口,接口WakeMainThread再发消息WM_NULL);工作线程进入等待执行完成的信号;
2.主线程接收到WM_NULL消息后,再将进入CheckSynchronize,检查队列中需要执行的函数,当执行完成后,设置执行完成信号;工作线程等待结束,继续往下运行;
3.主线程接收到WM_NULL并不影响其他消息的进入,因为TApplication.Run接口中不停地轮寻消息,消息也会不停地进入各自的消息处理过程; 除非程序睡眠了
4.工作线程调用Synchronize参数列表中执行过程,不应该将耗时的业务交给主线程执行,耗时的业务应该交给工作线程执行
5.工作线程无法代替的工作,可以用Synchronize交给主线程执行;
Synchronize执行过程的更多相关文章
- ASP.NET Web API 过滤器创建、执行过程(二)
ASP.NET Web API 过滤器创建.执行过程(二) 前言 前面一篇中讲解了过滤器执行之前的创建,通过实现IFilterProvider注册到当前的HttpConfiguration里的服务容器 ...
- ASP.NET Web API 过滤器创建、执行过程(一)
ASP.NET Web API 过滤器创建.执行过程(一) 前言 在上一篇中我们讲到控制器的执行过程系列,这个系列要搁置一段时间了,因为在控制器执行的过程中包含的信息都是要单独的用一个系列来描述的,就 ...
- ASP.NET Web API 控制器执行过程(一)
ASP.NET Web API 控制器执行过程(一) 前言 前面两篇讲解了控制器的创建过程,只是从框架源码的角度去简单的了解,在控制器创建过后所执行的过程也是尤为重要的,本篇就来简单的说明一下控制器在 ...
- Struts2拦截器的执行过程浅析
在学习Struts2的过程中对拦截器和动作类的执行过程一度陷入误区,特别读了一下Struts2的源码,将自己的收获分享给正在困惑的童鞋... 开始先上图: 从Struts2的图可以看出当浏览器发出请求 ...
- 通过源码了解ASP.NET MVC 几种Filter的执行过程
一.前言 之前也阅读过MVC的源码,并了解过各个模块的运行原理和执行过程,但都没有形成文章(所以也忘得特别快),总感觉分析源码是大神的工作,而且很多人觉得平时根本不需要知道这些,会用就行了.其实阅读源 ...
- Hadoop MapReduce执行过程详解(带hadoop例子)
https://my.oschina.net/itblog/blog/275294 摘要: 本文通过一个例子,详细介绍Hadoop 的 MapReduce过程. 分析MapReduce执行过程 Map ...
- 高程(4):执行环境、作用域、上下文执行过程、垃圾收集、try...catch...
高程三 4.2.4.3 一.执行环境 1.全局执行环境是最外层的执行环境. 2.每个函数都有自己的执行环境,执行函数时,函数环境就会被推入一个当前环境栈中,执行完毕,栈将其环境弹出,把控制器返回给之前 ...
- saltstack命令执行过程
saltstack命令执行过程 具体步骤如下 Salt stack的Master与Minion之间通过ZeroMq进行消息传递,使用了ZeroMq的发布-订阅模式,连接方式包括tcp,ipc salt ...
- Web APi之过滤器执行过程原理解析【二】(十一)
前言 上一节我们详细讲解了过滤器的创建过程以及粗略的介绍了五种过滤器,用此五种过滤器对实现对执行Action方法各个时期的拦截非常重要.这一节我们简单将讲述在Action方法上.控制器上.全局上以及授 ...
随机推荐
- spring整合mybatis,springMVC的0配置文件方式
0配置文件的形式主要是采用spring3.0提供的@configuration注解和spring容器在启动的时候会加载实现了WebApplicationInitializer的类,并调用其onStar ...
- YII 1.0 验证码
public function actions(){ return array ( ‘captcha’=> array( ‘class’=> ‘CCatpchaAction’, ‘heig ...
- 【bzoj3998】 TJOI2015—弦论
http://www.lydsy.com/JudgeOnline/problem.php?id=3998 (题目链接) 题意 给出一个字符串,求它的字典序第K小的子串是什么,分情况讨论不在同一位置的相 ...
- HTML 相同name 传递一个数组
今天发现一个很厉害的东西 在input表单中,name名称可以是一个,后面[],里面跟名称,和数组一样,传递到PHP中也是一个数组 <html> <body> <form ...
- MySQL生产库开发规范
MySQL开发规范 文件状态: [ ] 草稿 [√] 正式发布 [ ] 正在修改 文件标识: 当前版本: V1.0 作 者: 贺磊 完成日期: 2016-05-24 变更记录 序号 ...
- 手机淘宝中的那些Web技术-使用了类似PhoneGap的实现
Native APP与Web APP的技术融合已经逐渐成为一种趋势,使用标准的Web技术来开发应用中的某些功能,不仅可以降低开发成本,同时还可以方便的进行功能迭代更新.但是如何保证Web APP的流畅 ...
- jQuery wrap wrapAll wrapInner使用
jQuery wrap wrapAll wrapInner使用 <%@ page language="java" import="java.util.*" ...
- Web应用中监听者的通知顺序按照DD中的定义顺序
Web应用中监听者的通知顺序按照DD中的定义顺序: XML: <?xml version="1.0" encoding="UTF-8"?> < ...
- 如何使用Ninja快速编译LLVM和Clang
在使用Make工具编译LLVM是非常耗时的.往往需要三四个小时.但是使用goolge开源的ninja编译LLVM只需要10到20分钟. 本文以llvm3.3为例,演示在linux上编译和安装过程. 第 ...
- Swiper.js使用遇到的问题总结onSlideChangeEnd回调偶尔触发,偶尔不触发等;
Swiper 是一个开源免费的移动触摸插件. 在使用中遇到这样一个问题,记录一下. page 间切换效果 使用 fade 的时候,如果每个页面的大小不一样, 比如第一个页面全屏, 第二个页面比第一个小 ...