Delphi消息同步(同步到界面:VCL线程的同步方法 Synchronize(用消息来同步))

摘要:
正如你所想的,这样的程序将会非常难于调试,因为消息的来源实在太多了其次,由于VCL只用一个线程来访问它,那些用于把线程同步的代码就可以省略了,从而改善了应用程序的性能3.Synchronize()方法在TThread中有一个方法叫Synchronize(),通过它可以让子线程的一些方法在主线程中执行。因此,FMethod字段所指定的方法就在主线程内执行下图形象地说明了Synchronize()的内部机制和原理、4.用消息来同步可以利用在线程之间使用消息同步以替代TThread.Synchronize()方法。

先说一下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() 的内部机制和原理

Delphi消息同步(同步到界面:VCL线程的同步方法 Synchronize(用消息来同步))第1张

4.用消息来同步

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

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

转自:https://www.cnblogs.com/findumars/p/4972544.html?tdsourcetag=s_pcqq_aiomsg  

免责声明:文章转载自《Delphi消息同步(同步到界面:VCL线程的同步方法 Synchronize(用消息来同步))》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇国内外知名激光雷达公司盘点Elasticsearch的基础安装下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

java 虚拟机(五) jvm参数及调优

JVM 性能监控工具 一、Jinfo 1、用于查看正在运行的Java应用程序的扩展参数 `` jinfo -flags 线程号 `` 2、查看java系统参数 jinfo sysprops 线程号 二、Jstat 用于查看堆栈信息 jstat -class 线程号 其中 Loaded:加载class的数量 Bytes:所占用空间大小 Unloa...

java守护线程

守护线程: 线程分为用户线程和守护线程,当用户线程执行完毕后,程序就会结束,JRE判断程序是否执行结束的标准是所有的前台执线程行完毕了,而不管后台线程的状态 ,后台线程就是用来服务其他线程的线程,thread.setDaemon(true)必须在thread.start()之前设置; 执行情况: 主线程(main)执行结束后,用户线程可以继续执行直至执行完...

web 阶段的一些简答题

1.jsp 9个隐含对象 2. jsp 4大域对象 3.mybatis 中 #{} %{ } 的区别于联系 4. Servlet容器默认是采用单实例多线程的方式处理多个请求的: 5.Cookie 与Session 的异同 6. 请描述对web 服务器的理解(Tomcat),请列举出tomcat7下的目录以及各个目录的作用 7. 请描述 servlet与st...

子线程更新UI界面的2种方法

一、一般我们都会在子线程完成一些耗时的操作。 1、Android中消息机制: 2、知识点: Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message m...

见到的一篇IOCP流程 自己用demo实现了一下, 简单照抄,改动了一点点

要分析的实例分为两个线程: 分别是主线程(MAIN),还有一个是创建的线程(ServerThread) 1.主函数完成初始化工作:   1.1: (主线程)HANDLE hCompletion = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);    创建完成端口对象   1.2: (主线程...

阿里P6初面Java面试题,附带完整答案,赶紧搜藏

最强面试题推荐: 2020Java面试题及答案,命中率高达90% 1、锁可以锁在哪里? Java 为程序加锁的方式主要有两种:synchronized 与 Lock。 1. synchronized 可以修饰的作用域如下: - 非静态方法(加的锁为对象锁); - 静态方法(加的锁为类锁); - 代码块(对象锁与类锁均可); 2. Lock 采用 lock(...