VCL线程的同步方法 Synchronize(用消息来同步)
看本文时,可以同时参考: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;interfaceuses Classes;type TTestThread = class(TThread) private Answer: Integer; protected procedure GiveAnswer; procedure Execute; override; end;implementationuses 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, 0, Integer(PChar(S)));end; |
http://www.cnblogs.com/xumenger/p/4505104.html
VCL线程的同步方法 Synchronize(用消息来同步)的更多相关文章
- Delphi:与VCL同步(Synchronize()、用消息来同步)
看本文时,可以同时参考:Delphi中线程类 TThread实现多线程编程(事件.临界区.Synchronize.WaitFor……) 先说一下RTL和VCL RTL(Run-Time library ...
- android 进程/线程管理(四)----消息机制的思考(自定义消息机制)
关于android消息机制 已经写了3篇文章了,想要结束这个系列,总觉得少了点什么? 于是我就在想,android为什么要这个设计消息机制,使用消息机制是现在操作系统基本都会有的特点. 可是andro ...
- (原)Android在子线程用handler发送的消息,主线程是怎么loop到的?
来自知乎:https://www.zhihu.com/question/48130951?sort=created 大家都知道Android的Looper是ThreadLocal方式实现,每个线程 ...
- java 线程(四)线程安全 同步方法
package cn.sasa.demo2; import java.util.concurrent.ExecutionException; public class ThreadDemo { pub ...
- Java 基础 线程的Runnable接口 /线程的同步方法 /同步代码块
笔记: /**通过 Runnable接口来实现多线程 * 1. 创建一个实现runnable 接口的类 * 2. 在类中实现接口的run() 抽象方法 * 3. 创建一个runnable 接口实现类的 ...
- Netty客户端发送消息并同步获取结果
客户端发送消息并同步获取结果,其实是违背Netty的设计原则的,但是有时候不得不这么做的话,那么建议进行如下的设计: 比如我们的具体用法如下: NettyRequest request = new N ...
- delphi中线程应用之Synchronize
当一个线程在使用时,如果这个函数使用了Synchronize修钸的话就不允许别一个线程来调用这个函数,它的目的是避免多个子线程同时访问主线程资源.示例:procedure TTaskThread.Sh ...
- android 进程/线程管理(一)----消息机制的框架
一:android 进程和线程 进程是程序运行的一个实例.android通过4大主件,弱化了进程的概念,尤其是在app层面,基本不需要关系进程间的通信等问题. 但是程序的本质没有变,尤其是多任务系统, ...
- Android笔记(三十一)Android中线程之间的通信(三)子线程给主线程发送消息
先看简单示例:点击按钮,2s之后,TextView改变内容. package cn.lixyz.handlertest; import android.app.Activity; import and ...
随机推荐
- VS2012 快捷键 VS Resharper 设置
原文 http://www.cnblogs.com/skyangell/archive/2013/03/24/2979835.html 一直用Resharper插件,最近发现Ctrl+E,C快捷见被R ...
- VS下 dllimport与dllexport作用与区别
我相信写WIN32程序的人,做过DLL,都会很清楚__declspec(dllexport)的作用,它就是为了省掉在DEF文件中手工定义导出哪些函数的一个方法.当然,如果你的DLL里全是C++的类的话 ...
- JS获取按下的键盘字符
<html> <head> KeyPress Test!<hr> <script language="javascript"> fu ...
- 3Sum Smaller 解答
Question Given an array of n integers nums and a target, find the number of index triplets i, j, k w ...
- 图论专题训练1-D(K步最短路,矩阵连乘)
题目链接 /* *题目大意: *求出从i到j,刚好经过k条边的最短路; * *矩阵乘法的应用之一(国家队论文): *矩阵乘法不满足交换律,矩阵乘法满足结合律; *给定一个有向图,问从A点恰好走k步(允 ...
- ecshop 管理员不需要旧密码
- python多字符中找出最大匹配(网友处学习)
#如'abbcc','abbdd' 找到abba='abbcc'b='abbdd'from difflib import *s=SequenceMatcher(None,a,b)m=s.find_lo ...
- qt视图选择
# -*- coding: utf-8 -*- # python:2.x __author__ = 'Administrator' from PyQt4.Qt import * from PyQt4. ...
- Visual Studio 2015 使用ODP.net进行EF开发
刚转了新公司,以前公司都是用VS+MSSQL作为开发工具的 现在新公司由于数据库是Oracle,而且新公司比较小规模,开发团队也没有什么规范 访问数据库的方式一直使用ADO.net的DataTable ...
- Error creating bean with name 'memcachedClient'...java.lang.OutOfMemoryError
1,Tomcat启动报错例如以下: Caused by: org.springframework.beans.factory.BeanCreationException: Error creating ...