看本文时,可以同时参考: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. Box.net获5000万美元投资(SAAS博士)

    9月29日,据国外媒体报道,“云”存储服务商Box.net已经从Salesforce等投资者获得新一轮融资5000万美元. Box.net过去的投资者也参与了新一轮的融资.最终,在CRM巨人Sales ...

  2. 【转】一个从32位机器移植到64位机器时的c问题

    原文网址:http://www.jiancool.com/article/96402954887/ 最近工作中遇到了一个讨厌的问题,在32位机器上运行的好好的,但是在64位机器上,出现了诡异的 Seg ...

  3. c++ 10

    一.二叉树 1.基本特征 1)树型结构的最简模型,每个节点最多有两个子节点--左子节点和右子节点. 2)单根性,每个子节点有且仅有一个父节点,整棵树有且仅有一个根节点. 3)递归性,以任何一个节点为根 ...

  4. ActionResult解析

    原文地址:http://blog.csdn.net/gulijiang2008/article/details/7642213 ActionResult是一个抽象类, 在Action中返回的都是其派生 ...

  5. Longest Consecutive Sequence 解答

    Question Given an unsorted array of integers, find the length of the longest consecutive elements se ...

  6. c语言所有的errno枚举值含义

    可以通过以下代码,获取所有的错误码信息: #include <string.h> /* for strerror */ #include <errno.h> #include ...

  7. jquery 自动跳出列表

    先上效果图:当鼠标经过相亲会自动弹出取最新的10条数据

  8. 创建UILabel

    UILabelCreate.h #import <UIKit/UIKit.h> @interface UILabelCreate : UILabel /** * 创建UILabel 初始化 ...

  9. c++之 变量

    变量的基本操作 变量就是一个可以变化的量,变量由变量类型.变量名.初始值(可选)组成,例如: int abc = 10; 变量类型:int 变量名:abc 初始值:10 // 该值为可选项,在创建变量 ...

  10. pip安装lxml报错

    报错信息![](6a9f8494-8771-49c6-a663-cdcb2bdea123_files/0f4e7b93-9725-4c02-97a8-298d395b6169.png) 解决方法:`` ...