看本文时,可以同时参考:Delphi中线程类 TThread实现多线程编程(事件、临界区、Synchronize、WaitFor……)

先说一下RTL和VCL

  RTL(Run-Time library),运行时库,包括System、SysUtils、Math三个单元,提供的函数与语言、编译器、操作系统及进程有关

  RTL提供类之间继承于 TObject 和 RTL内部的类

  VCL(Visual Component Library),可视化组件库,包括Graphics、classes、Controls等与类和组件相关的单元

VCL不是线程安全的

  因为VCL不是线程安全的,所以对VCL的访问只能在主线程中。这将意味着:所有需要与用户打交道的代码都只能在主线程的环境中执行。这是其结构上明显的不足,并且这种需求看起来只局限在表面上,但它实际上有一些优点

  开发多线程项目的主要需要考虑的一点就是同步多线程使用资源,不要产生冲突,其实想Delphi的VCL组件也是一种资源,但是VCL不是线程安全的,不能让其他的线程使用,只能通过主线程来使用它

1.可能的一个应用场景

  比如在开发图形化界面的项目中,需要连接数据库,可以采用这样的策略:用主线程来绘制组件到图形化界面,而连接数据库的过程在子线程中实现。

  这时候能够保证就算在连接数据库的时候出现问题,子线程可能会去尝试一直连接,但是因为各个线程之间互不相干,各自执行各自的逻辑代码,所以不影响主线程绘制组件,所以窗体并不会卡住

  但是可能要在子线程中读取数据库中的数据来展示数据,这个时候,因为VCL 不是线程安全的,所以不能允许主线程(绘制组件)和子线程(想要去将从数据库中的数据“写”到界面上)同时去操作组件

  所以可能的解决方法(见 3.Synchronize() 方法)就是 使用Synchronize() 方法来调用子线程想要将数据“写到”界面的方法,这样就能保证这个方法实际上是在主线程中执行的(虽然它是子线程的方法,但是通过Synchronize() 方法可以实现将子线程的方法放到主线程中执行),这样就能保证不会出现多个线程使用VCL 组件

2.单线程用户界面的好处

  首先,只有一个线程能够访问用户界面,这减少了编程的复杂性。Win32 要求每个创建窗口的线程都要使用 GetMessage() 建立自己的消息循环。正如你所想的,这样的程序将会非常难于调试,因为消息的来源实在太多了

  其次,由于 VCL只用一个线程来访问它,那些用于把线程同步的代码就可以省略了,从而改善了应用程序的性能

3.Synchronize() 方法

  在 TThread中有一个方法叫Synchronize(),通过它可以让子线程的一些方法在主线程中执行。Synchronize() 的声明如下

procedure Synchronize(Method: TThreadMethod);

  参数Method 的类型是 TThreadMethod(这是一个无参数的过程),类型的声明如下

type
TThreadMethod = procedure of object;

  Method参数用来传递在主线程中执行的方法。以 TTestThread对象为例,如果要在一个编辑框中显示计算的结果。首先要在TTestThread中增加能对编辑控件的Text 属性进行修改的方法,然后,用Synchronize() 来调用此方法

  给这个方法取名 GiveAnswer(),下面列出例子的代码,其中包含了更新主窗体的编辑控件的代码

unit ThrdU;

interface
uses
Classes; type
TTestThread = class(TThread)
private
Answer: Integer;
protected
procedure GiveAnswer;
procedure Execute; override;
end; implementation
uses
SysUtils, Main; {TTestThread}
procedure TTestThread.GiveAnswer;
begin
MainForm.Edit1.Text := IntToStr(Answer);
end; procedure TTestThread.Execute;
var
I: Integer;
begin
FreeOnTerminate:= True;
for I:= 1 to 2000000 do
begin
if Terminated then Breadk;
Inc(Answer, Round(Abs(Sin(Sqrt(I))));
Synchronize(GiveAnswer);
end;
end;

  Synchronize() 的作用是在主线程中执行一个方法。

  当你在程序中第一次创建一个附属线程时,VCL 将会从主线程环境中创建和维护一个隐含的线程窗口。此窗口唯一的目的是把通过Synchronize() 调用的方法排队

  Synchronize() 把由Method 参数传递过来的方法保存在 TThread的 FMethod字段中,然后,给线程窗口发送一个CM_EXECPROC消息,并且把消息的lParam 参数设为self(这里是值线程对象)。当线程窗口的窗口过程收到这个消息后,它就调用 FMethod字段所指定的方法。由于线程窗口是在主线程内创建的,线程窗口的窗口过程也将被主线程执行。因此,FMethod字段所指定的方法就在主线程内执行

  下图形象地说明了 Synchronize() 的内部机制和原理

4.用消息来同步

  可以利用在线程之间使用消息同步以替代 TThread.Synchronize() 方法。可以使用API 函数SendMessage() 或 PostMessage() 来发送消息。例如下面一段用来在一个线程中设置另一个线程中的编辑框文本的代码

var
S: String;
begin
S:= 'hello from threadland';
SendMessage(SomeEdit.Handle, WM_SETTEXT, 0, Integer(PChar(S)));
end;

  

Delphi:与VCL同步(Synchronize()、用消息来同步)的更多相关文章

  1. VCL线程的同步方法 Synchronize(用消息来同步)

    看本文时,可以同时参考:Delphi中线程类 TThread实现多线程编程(事件.临界区.Synchronize.WaitFor……) 先说一下RTL和VCL RTL(Run-Time library ...

  2. Delphi的VCL组件库

    Visual Component Library的缩写(可视组件库)VCL是Visual Component Library的缩写,即可视组件库,它是Delphi,C++Builder等编程语言的基本 ...

  3. Netty客户端发送消息并同步获取结果

    客户端发送消息并同步获取结果,其实是违背Netty的设计原则的,但是有时候不得不这么做的话,那么建议进行如下的设计: 比如我们的具体用法如下: NettyRequest request = new N ...

  4. ActiveMQ producer同步/异步发送消息

    http://activemq.apache.org/async-sends.html producer发送消息有同步和异步两种模式,可以通过代码配置: ((ActiveMQConnection)co ...

  5. Delphi实现获取句柄并发送消息的方法(FindWindow、FindWindowEx、EnumChildWindows、SendMessage)

    Delphi实现获取句柄并发送消息的方法 本文以实例形式详细说明了Delphi获取句柄并发送消息的方法,具体用法说明如下: 查找另外一个窗口的句柄: handle := FindWindow(nil, ...

  6. Rsync同步、Rsync+Lsync实时同步

    Rsync同步.Rsync+Lsync实时同步 原创博文http://www.cnblogs.com/elvi/p/7658049.html #!/bin/sh #Myde by Elven @ #c ...

  7. mongosync同步1,oplog同步会读取其他集合同步

    使用mongosync同步数据     注意: 我下面的这个mongodb版本较低(3.2.16), 还可以用这个工具来同步数据.工具不支持更高版本的mongodb了. 使用方法: https://g ...

  8. 使用BestSync同步软件与坚果云同步

    坚果云的免费用户可以享受每个月的1G上传与3G下载流量,同时号称是国内唯一支持WebDAV的云.我的工作备份的文档不多,正好手头有BestSync同步软件可以用.决定试试BestSync的与WebDA ...

  9. js中ajax连接服务器open函数的另外两个默认参数get请求和默认异步(open的post方式send函数带参数)(post请求和get请求区别:get:快、简单 post:安全,量大,不缓存)(服务器同步和异步区别:同步:等待服务器响应当中浏览器不能做别的事情)(ajax和jquery一起用的)

    js中ajax连接服务器open函数的另外两个默认参数get请求和默认异步(open的post方式send函数带参数)(post请求和get请求区别:get:快.简单 post:安全,量大,不缓存)( ...

随机推荐

  1. 基于Emgu CV的人脸检测代码

    这个提供的代码例子是Emgu CV提供的源码里面自带的例子,很好用,基本不需要改,代码做的是人脸检测不是人脸识别,这个要分清楚.再就是新版本的Emgu CV可能会遇到系统32位和64位处理方式有区别的 ...

  2. 微信连WiFi expired timestamp 和sign错误小坑解决

    0.微信连WiFi需要时间戳毫秒,但是PHP本身没有自带这个函数.但是相对来说,Java和js获取毫秒时间戳就比较方便. 既然PHP没有,那么就自己写一个获取毫秒时间戳的函数,否则就会失败.实在懒得写 ...

  3. Ubuntu16.04编译Android6.0/cm13.0教程及相关错误解决办法

    一.必备工作 1.安装依赖库 sudo apt--dev libesd0-dev git-core gnupg flex bison gperf build-essential zip curl zl ...

  4. eclipse中设置文件默认打开方式

  5. windows下cmd记录MYSQL操作

    我们在cmd下操作MYSQL,当需要复制某条命令的时候,需要右键标记,然后选取,然后......各种不方便! 有没有比较方便的方式,可以将我们的操作记录自动的实时保存下来,当我们需要操作的时候,可以高 ...

  6. Redis模式匹配删除key

    Redis keys命令支持模式匹配,但是del命令不支持模式匹配,有时候需要根据一定的模式来模糊删除key,这时只能结合shell命令来完成了. 具体命令是: redis-cli KEYS &quo ...

  7. RabbitMQ consumer的一些坑

    坑 坑就像是恶梦,总是在最不设防的时候出现,打的你满地找牙.这里记录一些坑,遇到的朋友可以及时的跳出,避免带来损失. 使用事件方式去获取queue中的消息,然后再进行处理.这看起来没什么问题,但是如果 ...

  8. Js对map的操作

    var map = {}; // 赋值 var key = "key1"; var value = "value1"; map[key] = value; // ...

  9. Win7如何删除需要管理员权限才能删除的文件夹

    在Windows 7系统运行中.往往会遇到想要删除某个文件夹时,系统提示:文件夹访问被拒绝 你需要权限来执行此操作,如何才能删除此类文件夹呢? ------------------ --------- ...

  10. unity之初识shader

    自己做个总结先.当然文中很多内容都是从各位大神的文档当中看的.我只是站在巨人的肩膀上.       首先什么是shader?其实就是一个在显示屏当中的显示程序,俗称着色器.它可以定义物体在硬件显示屏当 ...