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交给主线程执行;

时间: 2024-12-24 07:54:57

Synchronize执行过程的相关文章

jsp的组成和执行过程

jsp由以下五个组成: Html静态页面 指令:  <%@  xxx  %> 小脚本:<%   xxx   %> 表达式:<% =       %> 声明:  <%!   xxx  %> 注释: html注释 <!-- html注释 -->  jsp注释 <%--jsp注释 --%> 脚本中的注释(java注释) /* 多行注释 */ //单行注释   sql注释 -- 执行过程: 翻译阶段 编译阶段 执行阶段 翻译   编译   执

一个C#程序的执行过程

可能很多人都知道我们把程序打包成dll就丢出去了,但是里面的具体的执行过程是怎么样的呢. 程序集是由元数据和IL组成的.IL是和CPU无关的语言,是微软的几个专家请教了外面的编译器的作则,开发出来的.IL比大多数机器语言都要高级一点.IL能够访问和操作对象类型,并提高了指令来初始化对象,调用对象上的虚方法以及直接操作数组元素. 比如下面这个例子 class Program { static void Main(string[] args) { Console.WriteLine("Hello&q

mysql(1)—— 详解一条sql语句的执行过程

SQL是一套标准,全称结构化查询语言,是用来完成和数据库之间的通信的编程语言,SQL语言是脚本语言,直接运行在数据库上.同时,SQL语句与数据在数据库上的存储方式无关,只是不同的数据库对于同一条SQL语句的底层实现不同罢了,但结果相同.这有点类似于java中接口的作用,一个接口可以有不同的实现类,不同的实现类对于接口中方法的实现方式可以不同,结果可以相同.这里SQL语言的作用就类似于java中的接口,数据库就类似于java中接口的实现类,SQL语句就类似于java接口中的方法.不同的是java中

高程(4):执行环境、作用域、上下文执行过程、垃圾收集、try...catch...

高程三 4.2.4.3 一.执行环境 1.全局执行环境是最外层的执行环境. 2.每个函数都有自己的执行环境,执行函数时,函数环境就会被推入一个当前环境栈中,执行完毕,栈将其环境弹出,把控制器返回给之前的执行环境. 二.作用域 1.每个执行环境,都对应一个自己的作用域. 2.每个执行环境,都能访问上一级的父级.父父级....作用域,称为 "作用域链" 3.执行代码时,会按照标识符沿着作用域链一级一级向上查找.如果找不到,则会报错 *标志符:执行时,使用到的变量或函数 三.上下文执行过程

通过源码了解ASP.NET MVC 几种Filter的执行过程

一.前言 之前也阅读过MVC的源码,并了解过各个模块的运行原理和执行过程,但都没有形成文章(所以也忘得特别快),总感觉分析源码是大神的工作,而且很多人觉得平时根本不需要知道这些,会用就行了.其实阅读源码是个很好的习惯,它不只停留在知道怎么用的阶段,而是让我们知道一系列的为什么,为什么这样设计,为什么这样使用....很多朋友应该看过<asp.net x 框架揭秘>这本书,确实不错,特别是边看源码边看书,可以有不小的收获.Ok,我不是大神,我只是心血来潮想看一下源码! 二.几种常见的Filter

JAVA编译和执行过程

Java代码编译是由Java源码编译器来完成,流程图如下所示: Java字节码的执行是由JVM执行引擎来完成,流程图如下所示: Java代码编译和执行的整个过程包含了以下三个重要的机制: Java源码编译机制 类加载机制 类执行机制 Java源码编译机制 Java 源码编译由以下三个过程组成: 分析和输入到符号表 注解处理 语义分析和生成class文件 流程图如下所示: 最后生成的class文件由以下部分组成: 结构信息.包括class文件格式版本号及各部分的数量与大小的信息 元数据.对应于Ja

JSP基本构成和执行过程

JSP(Java Server Page)页面是指扩展名为 .jsp 的文件. JSP是服务器端运行的页面,不像html文件直接就可以在浏览器中运行.JSP页面必须部署到web容器中编译成Servlet才能执行,可以说,JSP就是Servlet的一种形式. 事实上,JSP是Servlet发展的产物,关于JSP和Servlet的关系以后再在博客中介绍. JSP基本页面由指令标签,HTML标记语言,注释,Java代码,JSP动作标签5个部分组成. 1.JSP指令标签不会产生任何内容输出到网页中,主要

NameNode跟secondarynamenode的执行过程

一.NameNode详解 文件包括: fsimage:元数据镜像文件.存储某一时段NameNode内存元数据信息. edits:操作日志文件. fstime:保存最近一次checkpoint的时间 以上这些文件是保存在linux的文件系统中. /data/hadoop/hdfs/name [[email protected] name]$ ls current  image  in_use.lock  previous.checkpoint [[email protected] name]$ c

Linux下C语言执行过程(预处理,编译,汇编,链接,执行)

1.C语言的执行过程包括5个步骤:分别是:预处理,编译,汇编,链接,执行 第一步:编写C源代码,截图如下: 2.预处理,命令为:gcc -E variable.c -o variable.i(这步的作用是文件的展开和宏替换),生成的文件类型是.i类型的. 3.编译:命令为:gcc -S variable.i -o variable.s,这里的.s文件就成了会变语言,截图如下: 4.汇编,命令是:gcc -c variable.s -o variable.o,截图如下: 5,链接:命令:gcc -