在Delphi中创建线程,请一定使用BeginThread()代替CreateThread()创建线程!(更好的管理异常)
在Delphi中创建线程,请一定使用BeginThread()代替CreateThread()创建线程!
如果直接使用Win32的API函数CreateThread()创建多个线程,也是可以创建的。但是,你应该明白,在每个线程中动态分配和销毁内存块,是需要同步保护的。Delphi语言中有一个在使用多线程环境下至关重要的全局变量IsMultiThread,系统在进行内存分配的时候,根据IsMultiThread变量值判断当前是否使用在多线程环境下,如果该变量为True,哪么,系统在分配和销毁内存的时候,是要进行同步保护的。相反,则不用同步保护。
所以,如果你直接使用CreateThread()创建线程,一定要记得手动将IsMultiThread变量置为True。要不然你就会经常发现系统内存非法访问错误!如果你使用Delphi中的BeginThread()创建线程,这个BeginThread()的实现如下:
function BeginThread(SecurityAttributes: Pointer; StackSize: LongWord;
ThreadFunc: TThreadFunc; Parameter: Pointer; CreationFlags: LongWord;
var ThreadId: LongWord): Integer;
var
P: PThreadRec;
begin
New(P);
P.Func := ThreadFunc;
P.Parameter := Parameter;
IsMultiThread := TRUE;
Result := CreateThread(SecurityAttributes, StackSize, @ThreadWrapper, P,
CreationFlags, ThreadID);
end;
看见了吗?上面已经将IsMultiThread := TRUE;这样就保证了在多线程下,内存使用的安全。
使用BeginThread()函数替代CreateThread()的另一个重要理由就在上面的的代码段中,你发现了吗?BeginThread()函数内部在调用CreateThread()的时候,哪个线程函数指针用的是@ThreadWrapper,参数用的是P,而 P: PThreadRec; 是一个结构体指针,结构体内部分别才是线程函数和线程函数参数。
ThreadWrapper函数实现如下:
{$IFDEF MSWINDOWS}
function ThreadWrapper(Parameter: Pointer): Integer; stdcall;
{$ELSE}
function ThreadWrapper(Parameter: Pointer): Pointer; cdecl;
{$ENDIF}
asm
{$IFDEF PC_MAPPED_EXCEPTIONS}
{ Mark the top of the stack with a signature }
PUSH UNWINDFI_TOPOFSTACK
{$ENDIF}
CALL _FpuInit
PUSH EBP
{$IFNDEF PC_MAPPED_EXCEPTIONS}
XOR ECX,ECX
PUSH offset _ExceptionHandler
MOV EDX,FS:[ECX]
PUSH EDX
MOV FS:[ECX],ESP
{$ENDIF}
{$IFDEF PC_MAPPED_EXCEPTIONS}
// The signal handling code in SysUtils depends on being able to
// discriminate between Delphi threads and foreign threads in order
// to choose the disposition of certain signals. It does this by
// testing a TLS index. However, we allocate TLS in a lazy fashion,
// so this test can fail unless we've already allocated the TLS segment.
// So we force the allocation of the TLS index value by touching a TLS
// value here. So don't remove this silly call to AreOSExceptionsBlocked.
CALL AreOSExceptionsBlocked
{$ENDIF}
MOV EAX,Parameter
MOV ECX,[EAX].TThreadRec.Parameter
MOV EDX,[EAX].TThreadRec.Func
PUSH ECX
PUSH EDX
CALL _FreeMem
POP EDX
POP EAX
CALL EDX
{$IFNDEF PC_MAPPED_EXCEPTIONS}
XOR EDX,EDX
POP ECX
MOV FS:[EDX],ECX
POP ECX
{$ENDIF}
POP EBP
{$IFDEF PC_MAPPED_EXCEPTIONS}
{ Ditch our TOS marker }
ADD ESP, 4
{$ENDIF}
end;
ThreadWrapper函数是使用BASM汇编代码实现,如果你熟悉BASM汇编,你就知道,前面的代码,是BASM汇编中函数传参数的约定,后面的才是重点,它内部实现了当执行线程函数出现异常错误时,转化为异常的机制。
如果你直接使用CreateThread()创建线程,当然就不会有执行线程函数提供触发异常这样的好处,这才是使用BeginThread()函数替代CreateThread()的最重要原因,也是根本原因。
线程中的异常机制很重要吗?当然重要!因为线程函数只是一个执行函数过程体,当在这个函数的执行过程中,如果发生异常,程序就会退出当前线程函数,也就是线程会终止。所以在线程中提供异常机制,并让我们在线程中可以捕获处理,是非常至关重要的。
http://blog.csdn.net/zang141588761/article/details/51654748
在Delphi中创建线程,请一定使用BeginThread()代替CreateThread()创建线程!(更好的管理异常)的更多相关文章
- Delphi中实现MDI子窗体(转)
Delphi中实现MDI子窗体 用MDI实现浏览子窗口,具有窗口管理功能,同屏观看多个网页的内容 ① 多文档窗体(MDI) MDI窗体是一种具有主子结构的窗体体系,微软的Word便是其中的一 ...
- Delphi中线程类TThread实现多线程编程2---事件、临界区、Synchronize、WaitFor……
接着上文介绍TThread. 现在开始说明 Synchronize和WaitFor 但是在介绍这两个函数之前,需要先介绍另外两个线程同步技术:事件和临界区 事件(Event) 事件(Event)与De ...
- 转发 Delphi中线程类TThread 实现多线程编程
Delphi中有一个线程类TThread是用来实现多线程编程的,这个绝大多数Delphi书藉都有说到,但基本上都是对TThread类的几个成员作一简单介绍,再说明一下Execute的实现和Synchr ...
- Delphi中的线程类 - TThread详解
Delphi中的线程类 - TThread详解 2011年06月27日 星期一 20:28 Delphi中有一个线程类TThread是用来实现多线程编程的,这个绝大多数Delphi书藉都有说到,但基本 ...
- Delphi CreateProcess 创建一个新的进程和它的主线程
Delphi CreateProcess WIN32API函数CreateProcess用来创建一个新的进程和它的主线程,这个新进程运行指定的可执行文件 CreateProcess百科名片 WIN32 ...
- Delphi中的线程类(转)
Delphi中的线程类 (转) Delphi中有一个线程类TThread是用来实现多线程编程的,这个绝大多数Delphi书藉都有说到,但基本上都是对 TThread类的几个成员作一简单介绍,再说明一下 ...
- Delphi中线程类TThread实现多线程编程1---构造、析构……
参考:http://www.cnblogs.com/rogee/archive/2010/09/20/1832053.html Delphi中有一个线程类TThread是用来实现多线程编程的,这个绝大 ...
- Delphi中DLL的创建和使用
参考:http://blog.csdn.net/ninetowns2008/article/details/6311663 结合这篇博客:http://www.cnblogs.com/xumenger ...
- Delphi中DLL的创建和使用(转)
Delphi中DLL的创建和使用 1.DLL简介: 2.调用DLL: 3.创建DLL: 4.两个技巧: 5.初始化: 6.例外处理. 1.DLL简介 ...
随机推荐
- easyexcel 读写测试
<dependencies> <dependency> <groupId>com.alibaba</groupId> <artifactId> ...
- PPT之SmartArt功能
在PPT中,我们经常看到这样的漂亮的组合图标: 他们是怎么做出来的呢?其实用ppt自带的SmartArt功能就能做出来了. Tips:SmartArt可以直接先选择组合图标再填文字,还可以写好了文字, ...
- HDU 1224 Free DIY Tour - 最短路
传送门 题目大意: 一个有向图(n + 1相当于1),每个点有一个权值(可以认为1和n+1权值为0),求从1走到n+1(相当于走回1)的最大路径权值和是多少,输出方案. 题目分析: 最短路问题,输出方 ...
- ssh远程连接docker中的 linux container
ssh远程连接docker中的container 由于工作需要,要远程连接Container,本地机器是windows,以下为解决步骤: 1. 环境 本地:Windows ↓ Docker版本1. ...
- Android菜鸟的成长笔记(16)——Service简介
Service是Android四大组件之一 1.Service与Activity的区别在:Service一直在后台运行,没有用户界面. 2.选择Activity与Service的标准:如果某个程序组件 ...
- 【29.82%】【codeforces 703D】Mishka and Interesting sum
[题解] 题意: 给n个数字组成有序数列; 给m个询问. 对于每个询问区间.输出这个区间里面出现次数为偶数次的所有数的异或值; 做法: 我们可以先求出这段区间里面所有(包括重复的数字)数字的异或值p1 ...
- CMake 添加头文件目录,链接动态、静态库(添加子文件夹)
CMake支持大写.小写.混合大小写的命令. 当编译一个需要第三方库的项目时,需要知道: 去哪找头文件(.h),-I(GCC) INCLUDE_DIRECTORIES() 去哪找库文件(.so/.dl ...
- lzugis——Arcgis Server for JavaScript API在自己的定义InfoWindow
你看到这个标题嫌烦.因为我最近一直与研究问题,相关文章使这些也可以只,同时要读我文章的朋友.我的文章能够给你带来帮助. 在相关的内部的前两篇文章,达到InfoWindow经div实现的东西,成Info ...
- 0-1分布(伯努利分布)、n 重伯努利分布(二项分布)
1. 0-1 分布(伯努利分布) 0-1分布又名两点分布,或叫伯努利分布. P{X=k}=pk(1−p)1−k 其中 k=0,1. 伯努利分布未必一定是 0-1 分布,也可能是 a-b 分布,只需满足 ...
- 并发-Java并发编程基础
Java并发编程基础 并发 在计算机科学中,并发是指将一个程序,算法划分为若干个逻辑组成部分,这些部分可以以任何顺序进行执行,但与最终顺序执行的结果一致.并发可以在多核操作系统上显著的提高程序运行速度 ...