学习笔记: Delphi之线程类TThread

新的公司接手的第一份工作就是一个多线程计算的小系统。也幸亏最近对线程有了一些学习,这次一接手就起到了作用。但是在实际的开发过程中还是发现了许多的问题,比如挂起与终止的概念都没有弄明白,导致浪费许多的时间。

TThread-简单的开始

在Delphi的VCL中封装了一个TThread类用于多线程的开发,这样比较符合面向对象的思想,同时又可以提高开发效率,一般的情况下开发都是通过派生这个类来实现多线程。所以重点还在这个类TThread上:

简单的看一眼,这个类倒也简单,就是封装了线程的API,通过一个ThreadProc函数来完成了多线程整个过程。很容易就能派生一个线程类:

TMyThread = class(TThread)
  private
    FCount: Integer;
    FOnShowValue: TGetStrProc;
  protected
    procedure Execute; override;
  public
    constructor Create;
    property Count: Integer read FCount;
    property OnShowValue: TGetStrProc read FOnShowValue write FOnShowValue;
  end;

{ TMyThread }
 
constructor TMyThread.Create;
begin
  inherited Create(False);
  FCount := 0;
  FreeOnTerminate := False;
end;
 
procedure TMyThread.Execute;
begin
  while not self.Terminated do
  begin
    Inc(FCount);
 
    if Assigned(FOnShowValue) then
      FOnShowValue(IntToStr(FCount));
 
    Sleep(100);
  end;
end;

代码中只覆盖了一个Execute方法即可,其他的代码都是业务相关的代码,还是非常简单好用。

线程挂起

线程还支持挂起的功能,即让CPU将线程中断,保留现场,不再分配时间片,这样线程就像死了一般,直到再次唤醒线程再恢复现场继续执行。

线程终止

在Delphi的TThread类实现中,可以通过一个Terminate方法来让线程终止。但事实上Terminated只是一个标识而已,在线程启动时这个标识为False。

线程释放 一般线程创建后运行完会自动释放,所以这里的类里我设置FreeOnTerminate := False;,这样线程对象就不会自动释放,这样做的好处就是可以由线程对象以外的代码来管理线程的生命周期,如果有的代码需要控制线程对象的生命周期就可以用这个属性来让线程不自己释放。

ThreadProc-源代码分析

function ThreadProc(Thread: TThread): Integer;
var
  FreeThread: Boolean;
begin
{$IFDEF LINUX}
  if Thread.FSuspended then sem_wait(Thread.FCreateSuspendedSem);
{$ENDIF}
  try
    if not Thread.Terminated then
    try
      Thread.Execute;
    except
      Thread.FFatalException := AcquireExceptionObject;
    end;
  finally
    FreeThread := Thread.FFreeOnTerminate;
    Result := Thread.FReturnValue;
    Thread.FFinished := True;
    Thread.DoTerminate;
    if FreeThread then Thread.Free;
{$IFDEF MSWINDOWS}
    EndThread(Result);
{$ENDIF}
{$IFDEF LINUX}
    // Directly call pthread_exit since EndThread will detach the thread causing
    // the pthread_join in TThread.WaitFor to fail.  Also, make sure the EndThreadProc
    // is called just like EndThread would do. EndThreadProc should not return
    // and call pthread_exit itself.
    if Assigned(EndThreadProc) then
      EndThreadProc(Result);
    pthread_exit(Pointer(Result));
{$ENDIF}
  end;
end;

对于TThread的一个关键部分就是这个ThreadProc方法,它是线程创建时传给系统API的回调函数;Delphi中通过这个方法完成了一个核心的功能,可以看到代码中调用了Execute方法。这也就是为什么派生类只要覆写这个方法的原因。

所以从代码也可以看出,线程启动后代码是顺序执行的,代码走完就结束了,所以为了让线程能够一直在运行就要在Execute方法里加上一个死循环,保证线程一直在运算,直到接收到Terminated时才让线程结束掉。所以Terminated的真正作用在这呢,需要开发者自己来控制,当然这样也就变的非常灵活了。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏柠檬先生

Angularjs基础(三)

    AngularJS ng-model 指令     ng-model 指令用于绑定应用程序数据到HTML 控制器(input,select,text...

22350
来自专栏lulianqi

直接修改托管堆栈中的type object pointer(类型对象指针)

最初的我简单认为数据的类型就是定义时字段的类型修饰决定的(回来发现这种观点是绝对错误的)

16610
来自专栏大内老A

ASP.NET Core的配置(2):配置模型详解

在上面一章我们以实例演示的方式介绍了几种读取配置的几种方式,其中涉及到三个重要的对象,它们分别是承载结构化配置信息的Configuration,提供原始配置源数...

22290
来自专栏大内老A

通过定义UnityContainer扩展变”Explicit Interception”为”Automatic Interception”

Unity是微软P&P部门开发的一个轻量级IoC框架,通过Interception机制可以实现基于三种拦截机制的AOP。不过Unity仅仅提供“显式”拦截机制,...

21890
来自专栏大内老A

[ASP.NET MVC]如何定制Numeric属性/字段验证消息

对于一个Numeric属性/字段,ASP.NET MVC会自动进行数据类型的验证(客户端验证),以确保输入的是一个有效的数字,但是呈现在页面上的错误消息总是一段...

237100
来自专栏技术博客

Asp.Net Web API 2第十二课——Media Formatters媒体格式化器

阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.h...

8930
来自专栏noteless

ServletRequest HttpServletRequest 请求方法 获取请求参数 请求转发 请求包含 请求转发与重定向区别 获取请求头字段

实际为   HttpServletRequest  或者  ServletRequest,   两者都为接口

23850
来自专栏技术博客

Asp.Net Web API 2第八课——Web API 2中的属性路由

阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.h...

10840
来自专栏技巅

Redis第一个版本源码分析-启动过程分析1

19650
来自专栏云瓣

Node.js 异步异闻录

提到 Node.js, 我们脑海就会浮现异步、非阻塞、单线程等关键词,进一步我们还会想到 buffer、模块机制、事件循环、进程、V8、libuv 等知识点。本...

42180

扫码关注云+社区

领取腾讯云代金券