Delphi管理多线程之线程局部存储:threadvar
尽管多线程能够解决许多问题,但是同时它又给我们带来了很多的问题。其中主要的问题就是:对全局变量或句柄这样的全局资源如何访问?另外,当必须确保一个线程中的某些事件要在另一个线程中的其他时间之前(或之后)发生时,该怎么办?这里将讲解通过使用由 Delphi提供的线程局部存储和 A P I为线程提供同步的方法。
这里先讲线程局部存储,下一篇再讲线程同步
线程局部存储
由于每个线程都代表一个不同的执行路径,因此,最好有一种只限于一个线程内部使用的数据存储方式。要实现上述目的有三种方式:
1)第一种也是最简单的一种方式是局部变量((基于栈)。
由于每个线程都在各自的栈中,各个线程都将有一套局部变量的副本,这样,就不会互相影响。
2)第二种方式就是把有关信息保存在各自的线程对象中
3)第三种方式就是用Delphi的关键字 threadvar 来声明变量,以利用操作系统级的线程局部存储
1.把信息保存在TThread派生对象中
将相关信息保存在TThread派生对象中,这是一种线程局部存储可选的技术。相对于使用关键字threadvar的技术,这种方式更加简单、更加有效。例如,你可以在一个线程对象中加入下列信息
type
TMyThread = class(TThread)
private
FLocalInt: Integer;
FLocalStr: String;
..
..
end;
提示:由于访问线程对象中的数据比访问线程局部变量快10倍,因此,你应当尽可能地把线程专用的信息保存在线程对象中。对于那些只在过程或函数的生存期有意义的变量,应当把它们声明为局部变量
2.threadvar:API线程局部存储
在前面讲到:虽然对于局部变量,在每个线程中都有一个副本,然而应用程序的全局变量是被所有线程所共享的。例如,假设现在还有一个用于设置和显示一个全局变量的值的过程。如果传递一个字符串给它,就设置这个全局变量;如果传递一个空字符串给它,就显示这个全局变量的值。这个过程定义如下:
var
GolbalStr: String;
procedure SetShowStr(const S: String);
begin
if S = '' then
MessageBox(0, PChar(GlobalStr), 'The string is ...', MB_OK)
else
GlobalStr:= S;
end;
如果在某段代码中调用这个过程,则可能出现一些问题。因为在调用它时,可以先设置而后显示。可问题是,有可能有两个或更多的线程存在。当一个线程调用此过程来设置字符串时,而另一个线程也可能调用此过程来设置GlobalStr 变量的值。当操作系统把CPU时间又分配给前一个线程时,该线程所设置的值有可能已经令人失望的丢失了
为了解决这个问题,Win32 提供了一种称为线程局部存储的方式,它能使你在第一个运行的线程中创建一个全局变量的拷贝。Delphi利用关键字 threadvar封装此功能。
在threadvar关键字下你可以声明任何局部存储的变量。下面是局部变量GlobalStr的声明:
threadvar
GlobalStr: String;
下面演示了线程局部存储的用法。在程序的主窗体上有一个按钮,单击此按钮,就设置并显示 GlobalStr变量的值。然后再创建一个线程,GlobalStr变量的值有被设置并显示。在创建了一个线程之后,从主线程再次设置并显示GlobalStr变量的值
先后用var 和 threadvar来声明 GlobalStr变量并运行此程序,你会在输出中看到不同
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls; type
TMainForm = class(TForm)
Button1:TButton;
procedure Button1Click(Sender: TObject);
private
{...}
public
{...}
end; var
MainForm: TMainForm; implementation
{$R *.DFM} var
//threadvar
GlobalStr: String; type
TTLSThread = class(TThread)
private
FNewStr: String;
protected
Procedure Execute; override;
public
cpnstructor Create(Const ANewStr: String);
end; procedure SetShowStr(const S: String);
begin
if S = '' then
MessageBox(0, PChar(GlobalStr), 'The string is ...', MB_OK)
else
GlobalStr:= S;
end; constructor TTLSThread.Create(const ANewStr: String);
begin
FNewStr:= ANewStr;
inherited Create(False);
end; procedure TTSThread.Execute;
begin
FreeOnTerminate:= True;
SetShowStr(FNewStr);
SetShowStr('');
end; procedure TMianForm.Button1Click(Sender: TObject);
begin
SetShowStr('Hello World');
SetShowStr('');
TTLSThread.Create('Dilbert');
Sleep(100);
SetShowStr('');
end; end.
注意:演示程序中,在创建了线程之后,调用了一个Win32 API过程 Sleep()。此过程的声明如下
procedure Sleep(dwMillseconds: DWORD); stdcall;
Sleep()过程用来告诉操作系统,当前的线程在参数 dwMillseconds指定的时间内不需要分配任何CPU时间。插入这个调用是使很多的任务在发生时,使执行哪个线程有一些随机性
通常,可以把参数dwMillseconds设置为0,尽管,这并没有使当前的线程真的“睡眠”,但是它使操作系统把CPU时间分给其他优先级相等或者更高的线程
要小心Sleep()神秘的时间调整问题。Sleep()可能会是你的机器出现特别的问题。这种问题在另一台机器上可能无法再现
Delphi管理多线程之线程局部存储:threadvar的更多相关文章
- Java多线程系列——线程池原理之 ThreadPoolExecutor
ThreadPoolExecutor 简介 ThreadPoolExecutor 是线程池类. 通俗的讲,它是一个存放一定数量线程的线程集合.线程池允许多个线程同时运行,同时运行的线程数量就是这个线程 ...
- OS之进程管理---多线程模型和线程库(POSIX PTread)
多线程简介 线程是CPU使用的基本单元,包括线程ID,程序计数器.寄存器组.各自的堆栈等,在相同线程组中,所有线程共享进程代码段,数据段和其他系统资源. 传统的的单线程模式是每一个进程只能单个控制线程 ...
- 线程局部存储(TLS)
线程局部存储(TLS) 2011-10-11 09:59:28| 分类: Win32---API | 标签:tls |举报 |字号 订阅 什么是线程局部存储 众所周知,线程是执行的单元,同 ...
- 线程局部存储tls的使用
线程局部存储(Thread Local Storage,TLS)主要用于在多线程中,存储和维护一些线程相关的数据,存储的数据会被关联到当前线程中去,并不需要锁来维护.. 因此也没有多线程间资源竞争问题 ...
- Delphi 中多线程同步的一些处理方法
Delphi 中多线程同步的一些处理方法 当创建了多个线程,并且多个线程都要访问同一资源,,就有可能出现混乱,于是用Synchronize来控制,使同一时间只有一个线程使用那部分资源,Synchr ...
- C#多线程之线程池篇1
在C#多线程之线程池篇中,我们将学习多线程访问共享资源的一些通用的技术,我们将学习到以下知识点: 在线程池中调用委托 在线程池中执行异步操作 线程池和并行度 实现取消选项 使用等待句柄和超时 使用计时 ...
- C#多线程之线程同步篇3
在上一篇C#多线程之线程同步篇2中,我们主要学习了AutoResetEvent构造.ManualResetEventSlim构造和CountdownEvent构造,在这一篇中,我们将学习Barrier ...
- Java多线程开发系列之四:玩转多线程(线程的控制1)
在前文中我们已经学习了:线程的基本情况.如何创建多线程.线程的生命周期.利用已有知识我们已经可以写出如何利用多线程处理大量任务这样简单的程序.但是当应用场景复杂时,我们还需要从管理控制入手,更好的操纵 ...
- 多线程系列 线程池ThreadPool
上一篇文章我们总结了多线程最基础的知识点Thread,我们知道了如何开启一个新的异步线程去做一些事情.可是当我们要开启很多线程的时候,如果仍然使用Thread我们需要去管理每一个线程的启动,挂起和终止 ...
随机推荐
- #Deep Learning回顾#之基于深度学习的目标检测(阅读小结)
原文链接:https://www.52ml.net/20287.html 这篇博文主要讲了深度学习在目标检测中的发展. 博文首先介绍了传统的目标检测算法过程: 传统的目标检测一般使用滑动窗口的框架,主 ...
- Caffe学习系列(11):数据可视化环境(python接口)配置
参考:http://www.cnblogs.com/denny402/p/5088399.html 这节配置python接口遇到了不少坑. 1.我是利用anaconda来配置python环境,在将ca ...
- fzu2188 状压dp
G - Simple String Problem Time Limit:2000MS Memory Limit:32768KB 64bit IO Format:%I64d & ...
- 2.5---链表来进行加法,链式A+B(CC150)
这里是用了自己的方法,和书本不一样. import java.util.HashSet; import java.util.Set; class ListNode{ int val; ListNode ...
- C++ 输出调试的一些技巧
主要利用了宏和stderr... #define enable_debug #ifdef enable_debug FILL some macros/functions here #else /// ...
- 什么情况下可以不写PHP的结束标签“?>”
我们经常看到有些PHP文件中的代码是只有开始标签,而没有结束标签的,那么什么情况下可以不写这个结束标签,而什么情况下必须写?先来看2个例子: 下面的代码正常运行: <?php echo 1234 ...
- jdbc mysql crud dao模型 sql注入漏洞 jdbc 操作大文件
day17总结 今日内容 l JDBC 1.1 上次课内容总结 SQL语句: 1.外键约束:foreign key * 维护多个表关系! * 用来保证数据完整性! 2.三种关系: * 一对多: * 一 ...
- ACM/ICPC 之 四道MST-Kruskal解法-练习题(POJ1251-POJ1287-POJ2031-POJ2421)
由于题目简单,部分题意写在代码中(简单题就应该多练英文...),且较少给注释,需要注意的地方会写在代码中,虽然四个题意各有千秋,但万变不离其宗,细细思考一番会发现四道题都属于很直接的最小生成树问题,由 ...
- ABAP 权限程序
检查用户销售区域与分销渠道的权限 AUTHORITY-CHECK OBJECT 'V_VBAK_VKO' ID 'VKORG' FIELD wa_all-vkorg ID 'V ...
- codeforces 499B.Lecture 解题报告
题目链接:http://codeforces.com/problemset/problem/499/B 题目意思:给出两种语言下 m 个单词表(word1, word2)的一一对应,以及 profes ...