首先看TThread源码中关于OnTerminate的代码:

public
....
property OnTerminate: TNotifyEvent read FOnTerminate write FOnTerminate;
...
end;

  再看Delphi自带的帮助手册中对于OnTerminate的解释:

Occurs after the thread's Execute method has returned and before the thread is destroyed.

property OnTerminate: TNotifyEvent;

Description

Write an OnTerminate event handler to execute code after the thread finishes executing. The OnTerminate event handler is called in the context of the main thread, which means CLX methods and properties can be called freely.

  翻译成中文的大致的解释就是:线程的该属性如果被赋值为一个方法,那么此方法将会在该线程的Execute方法执行完成并退出,但是线程还没有被释放之前执行。

  但是这里只是讲到它的使用,而且还可能只是多种可以使用的地方之一,但是OnTerminate是什么,它的原理是什么并没有讲到,所以还需要再去钻研。

  一个实际的例子:

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls; type
TForm1 = class(TForm)
btn1: TButton;
procedure btn1Click(Sender: TObject);
private
procedure ThreadDone(Sender: TObject);
public
{ Public declarations }
end; TTestThread = class(TThread)
protected
procedure Execute; override;
end; var
Form1: TForm1; implementation {$R *.dfm} const
MaxSize = 128;
var
NextNumber: Integer = 0;
DoneFlags: Integer = 0;
GlobalArray: array[1..MaxSize] of Integer;
CS: TRTLCriticalSection; function GetNextNumber: Integer;
begin
Result:= NextNumber;
Inc(NextNumber);
end; procedure TTestThread.Execute;
var
i: Integer;
begin
OnTerminate:= Form1.ThreadDone; //在这里设置OnTerminate属性的值为Form1的ThreadDone方法,
//表示在线程执行完Execute之后,还没有被释放之前,要紧接着执行Form1的ThreadDone方法。
EnterCriticalSection(CS);
for i:= 1 to MaxSize do
begin
GlobalArray[i]:= GetNextNumber;
Sleep(5);
end;
LeaveCriticalSection(CS);
end; procedure TForm1.ThreadDone(Sender: TObject);
var
i: Integer;
begin
inc(DoneFlags);
if DoneFlags = 2 then
begin
for i:= 1 to MaxSize do
lst1.Items.Add(IntToStr(GlobalArray[i]));
DeleteCriticalSection(CS);
end;
end; procedure TForm1.btn1Click(Sender: TObject);
begin
initializeCriticalSection(CS);
TTestThread.Create(False);
TTestThread.Create(False); end; end.

  先解释OnTerminate:在这里设置OnTerminate属性为Form1的ThreadDone方法,表示在线程执行完Execute之后,还没有被释放之前,要紧接着执行Form1的ThreadDone方法。

  再对线程的同步进行说明:这里使用临界区进行线程的同步,该例程会在点击按钮之后开启两个线程。

               每个线程都是对一个全局数组GlobalArray进行操作,使用了临界区的话,(看TForm1的btn1Click方法)虽然是连续开启两个线程,但是因为使用了临界区,而且是在线程的Execute中进行操作之前先进入临界区,所以当一个线程运行(也就是执行Execute方法)时,第一个线程进入临界区对全局数组GlobalArray进行性操作,那么另外一个线程就只能等待,等到第一个线程完成操作并且离开临界区之后(此时GlobalArray数组的值是从0到127)。第二个线程开始进入临界区,并且开始对GlobalArray进行操作,最后GlobalArray数组中的值是从128到255。

               通过使用临界区就可以保证多个线程不能同时对一个资源进行操作,而如果没有使用临界区对线程进行同步的话,那么最后可能是线程1、线程2随机连续对数组进行操作(因为操作系统对线程的时间片的分配是随机的)(还有NextNumber这个全局变量也会被两个线程随机连续操作,可能造成冲突),最后的结果就是当两个线程都执行完成之后,GlobalArray数组中的值没有任何规律,所以这时候就不可能根据规则来控制线程,这时候开发出来的程序就是开发者所不能控制的,显然不利于程序的稳定性等。

               所以在多个线程会去操作同一个资源等情况的时候,必须对线程进行同步,保证线程的可控性。

Delphi多线程的OnTerminate属性(附加一个关于临界区线程同步的例子)的更多相关文章

  1. java 多线程总结篇3之——生命周期和线程同步

    一.生命周期 线程的生命周期全在一张图中,理解此图是基本: 线程状态图 一.新建和就绪状态 当程序使用new关键字创建了一个线程之后,该线程就处于新建状态,此时它和其他的Java对象一样,仅仅由Jav ...

  2. Java基础-多线程-③线程同步之synchronized

    使用线程同步解决多线程安全问题 上一篇 Java基础-多线程-②多线程的安全问题 中我们说到多线程可能引发的安全问题,原因在于多个线程共享了数据,且一个线程在操作(多为写操作)数据的过程中,另一个线程 ...

  3. 多线程,线程同步,synchronized关键字的用法

    一.什么是多线程 Java多线程实现方式主要有四种:继承Thread类.实现Runnable接口.实现Callable接口通过FutureTask包装器来创建Thread线程.使用ExecutorSe ...

  4. java多线程(2) 线程同步

    我们对线程访问同一份资源的多个线程之间,来进行协调的这个东西,就是线程同步.   例子1:模拟了多个线程操作同一份资源,可能带来的问题: package com.cy.thread; public c ...

  5. Java多线程之线程同步【synchronized、Lock、volatitle】

    线程同步 线程同步:当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作,而其他线程又处于等待状态,实现线程同步的方法有很多. ...

  6. Delphi多线程详解

    (整理自网络) Delphi多线程处理 1-1多线程的基本概念 WIN 98/NT/2000/XP 是个多任务操作系统,也就是:一个进程可以划分为多个线程,每个线程轮流占用CPU 运行时间和资源,或者 ...

  7. 【转】Delphi多线程编程

    文章来源: http://liukun966123.my.gsdn.net/2004/10/22/4797/ Delphi中有一个线程类TThread是用来实现多线程编程的,这个绝大多数Delphi书 ...

  8. delphi 多线程3

     多线程程序设计 我们知道,win95或winNT都是“多线程”的操作系统,在DELPHI .中,我们可以充分利用这一特性,编写出“多线程”的应用程序. 对以往在DOS或16位windows下写程序的 ...

  9. [转]Delphi多线程编程入门(二)——通过调用API实现多线程

    以下是一篇很值得看的关于Delphi多线程编程的文章,内容很全面,建议收藏. 一.入门 ㈠. function CreateThread(    lpThreadAttributes: Pointer ...

随机推荐

  1. Date类

    Date类 构造方法: Date():根据当前的默认毫秒值创建对象 Date(long date):根据给定的默认毫秒值创建对象 成员方法: public long getTime():获取时间,以毫 ...

  2. SQL中distinct的用法

    SQL中distinct的用法   1.作用于单列 2.作用于多列 3.COUNT统计 4.distinct必须放在开头 5.其他 在表中,可能会包含重复值.这并不成问题,不过,有时您也许希望仅仅列出 ...

  3. sed awk 样例

    sed [options] '[action]' filename options: -n:一般sed命令会把所有数据都输出到屏幕,如果加入此选项,则只会把经过sed命令处理的行输出到屏幕. -e:允 ...

  4. 分享公司DAO层数据库结果映射到对象的方法

    主题 前面写过一篇文章,分享了公司是怎么动态封装SQL查询条件的(http://www.cnblogs.com/abcwt112/p/5874401.html). 里面提到数据库查询结果二维数组最后是 ...

  5. Why did I have a recovery trip

    For more than a decade, I felt most at ease living out of a suitcase, never quite sure where I might ...

  6. GMOLO平板——如何安装新系统

    1.首先,此款平板采用intel处理器Z3735F,不支持Win7,XP,经过测试,Win8可以在此类笔记本及平板上运行,并非只能安装最新的Win10系统. 2.下载Win8 32位系统作为预备(GH ...

  7. Python 学习小结

    python 学习小结 python 简明教程 1.python 文件 #!/etc/bin/python #coding=utf-8 2.main()函数 if __name__ == '__mai ...

  8. AD域的安装(在Windows Server 2003中安装Active Directory)

    在Active Directory中提供了一组服务器作为身份验证服务器或登录服务器,这类服务器被称作域控制器(Domain Controller,简称DC).建立一个AD域的过程实际就是在一台运行Wi ...

  9. Dom元素的操作

    getElementById(): 获取有指定惟一ID属性值文档中的元素 getElementsByName(name): 返回的是数组 getElementsByTagName(): 返回具有指定标 ...

  10. Virus.Win32.Virlock.b分析

    0x00 样本说明 分析样本是被0b500d25f645c0b25532c1e3c9741667的样本感染得到.感染前的文件是Tcpview.exe,一款windows网络连接查看工具. 感染前后文件 ...