看本文时,可以同时参考: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() 的声明如下

1
procedure Synchronize(Method: TThreadMethod);

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

1
2
type
    TThreadMethod = procedure of object;

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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() 来发送消息。例如下面一段用来在一个线程中设置另一个线程中的编辑框文本的代码

1
2
3
4
5
6
var
    S: String;
begin
    S:= 'hello from threadland';
    SendMessage(SomeEdit.Handle, WM_SETTEXT, 0Integer(PChar(S)));
end;

  

http://www.cnblogs.com/xumenger/p/4505104.html

VCL线程的同步方法 Synchronize(用消息来同步)的更多相关文章

  1. Delphi:与VCL同步(Synchronize()、用消息来同步)

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

  2. android 进程/线程管理(四)----消息机制的思考(自定义消息机制)

    关于android消息机制 已经写了3篇文章了,想要结束这个系列,总觉得少了点什么? 于是我就在想,android为什么要这个设计消息机制,使用消息机制是现在操作系统基本都会有的特点. 可是andro ...

  3. (原)Android在子线程用handler发送的消息,主线程是怎么loop到的?

    来自知乎:https://www.zhihu.com/question/48130951?sort=created   大家都知道Android的Looper是ThreadLocal方式实现,每个线程 ...

  4. java 线程(四)线程安全 同步方法

    package cn.sasa.demo2; import java.util.concurrent.ExecutionException; public class ThreadDemo { pub ...

  5. Java 基础 线程的Runnable接口 /线程的同步方法 /同步代码块

    笔记: /**通过 Runnable接口来实现多线程 * 1. 创建一个实现runnable 接口的类 * 2. 在类中实现接口的run() 抽象方法 * 3. 创建一个runnable 接口实现类的 ...

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

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

  7. delphi中线程应用之Synchronize

    当一个线程在使用时,如果这个函数使用了Synchronize修钸的话就不允许别一个线程来调用这个函数,它的目的是避免多个子线程同时访问主线程资源.示例:procedure TTaskThread.Sh ...

  8. android 进程/线程管理(一)----消息机制的框架

    一:android 进程和线程 进程是程序运行的一个实例.android通过4大主件,弱化了进程的概念,尤其是在app层面,基本不需要关系进程间的通信等问题. 但是程序的本质没有变,尤其是多任务系统, ...

  9. Android笔记(三十一)Android中线程之间的通信(三)子线程给主线程发送消息

    先看简单示例:点击按钮,2s之后,TextView改变内容. package cn.lixyz.handlertest; import android.app.Activity; import and ...

随机推荐

  1. WPF可视化控件打印

    Introduction While coding an application that displays a detailed report in a ScrollViewer, it was d ...

  2. IOS 判断设备类型

    - (NSString*)deviceString { // 需要#import "sys/utsname.h" struct utsname systemInfo; uname( ...

  3. Oracle通过指令创建用户

    Oracle作为世界上使用最广泛的关系数据库,对于客户很多每天海量数据的公司是首要选择.我们公司在双十一期间,曾发生过每网点每天1G多的扫描数据量,全国有六千多个网点,每天每时不停读写数据库,而数据库 ...

  4. android CMWAP, CMNET有何差别

    什么是CMNET,什么是CMWAP? 答:CMWAP和CMNET仅仅是中国移动为其划分的两个GPRS接入方式.中国移动对CMWAP作了一定的限制,主要表如今CMWAP接入时仅仅能訪问GPRS网络内的I ...

  5. hdu 4427 Math Magic

    一个长了一张数学脸的dp!!dp[ i ][ s ][ t ] 表示第 i 个数,sum为 s ,lcm下标为 t 时的个数.显然,一个数的因子的lcm还是这个数的因子,所以我们的第三维用因子下标代替 ...

  6. 男同胞爱小秘籍--作为爱他的女朋友了几天C规划

    各位男同胞,不知道你的女朋友没有在过去的一问天,你这个问题~~ 场景重现: 女友:"今天天气不错." 你们:"对" 女友:"今天是我们知道它的最初几天 ...

  7. css-下拉菜单案例

    <!DOCTYPE html>CSS4-布局2-display下拉菜单案例 <style>.xiala{width:200px;background:#ddd;}.xiala ...

  8. css中的伪类

    伪类用于向某些选择器添加一些特殊效果. 1):focus 伪类在元素获得焦点的时向元素添加特殊样式.一般用于输入文本域,按钮,以及超链接. a:focus{color:red;}超链接字体为红色 in ...

  9. Linq 标准查询操作符三

    本文介绍了LINQ标准查询操作符.没有这些操作符,LINQ就不会存在.本文为理解这些操作符的功能提供了很好的基础.了解它们将会很有帮助,因为LINQ的各种Provider都是基于这些操作符来完成各自丰 ...

  10. C#索引器:在集合或数组中取出某一个元素 举例 _【转】

    Garmmar: [访问修饰符] 数据类型 this[参数列表] { get { 获取索引器的内容 } set { 设置索引器的内容 } } Eg: <span style="font ...