• Delphi ThreadPool 线程池(Delphi2009以上版本适用)


    http://blog.sina.com.cn/s/blog_6250a9df0101kref.html

    在网上查找Delphi线程池,结果发现寥寥无几。

    看了半天源代码,弄得一头雾水,觉得不容易理解和使用,于是自己想写一个线程池。

    什么样的线程池更好呢?

    我觉得使用起来要可靠,并且一定要简单,这样才是更好的。

    我写的线程池就是这样一个标准,使用非常简单,只传入自己要执行的方法就可以了,

    其实大家最后就是关注自己要操作的方法,其余的交给线程池。全部源代码如下:

    {
      {单元:ThreadPoolUint}
      {说明:线程池}
      //
      {Rev. 开发日期      开发者   EMail}
      {Ver.1.0.0   2011/05/05    孙玉良   sunylat@gmail.com}
    }
    
    unit ThreadPoolUint;
    
    { 定义多线程共享读独占写条件编译}
    {$DEFINE MULTI_THREAD_WRITE_READ}
    
    interface
    
    uses System.Classes, System.SysUtils, System.Math, System.Generics.Collections,
      Vcl.Forms;
    
    type
    
      { 要执行任务的记录}
      TaskRec = record
        isSynchronize : Boolean; { 是否需要同步执行}
        TaskProc : TThreadProcedure; { 要执行任务的方法}
      end;
    
      { 执行具体任务线程}
      TExecuteThread = class( TThread )
      private
        FProc : TThreadProcedure; { 要执行的任务方法}
        FIsCanTask : Boolean; { 是否可以执行任务}
        FIsSynchronize : Boolean; { 是否用同步执行}
    
        procedure showThreadID; { 显示线程编号(测试使用)}
      protected
        procedure Execute; override;
      public
        constructor Create( CreateSuspended : Boolean ); overload;
      public
        procedure StartTask( task : TaskRec ); { 执行任务}
      end;
    
      { 线程池类(单例模式的类,做为全局使用的类)}
      ThreadPool = class( TObject )
      private
    {$IFDEF MULTI_THREAD_WRITE_READ}
        FMREWSync : TMREWSync; { 共享读独占写变量}
    {$ENDIF}
        FTaskQueue : TQueue< TaskRec >; { 要执行任务队列}
        FTaskThreadList : TList< TExecuteThread >; { 执行任务线程List}
        FThreadMin : Integer; { 最小线程数量}
        FThreadMax : Integer; { 最大线程数量}
    
        { 共享读独占写方法}
        procedure BeginWrite; { 独占写开始}
        procedure EndWrite; { 独占写结束}
        procedure BeginRead; { 共享读开始}
        procedure EndRead; { 共享读结束}
    
        procedure StopTaskAndFree; { 停止执行任务并释放相关资源}
    
      protected
        constructor CreateInstance( const minCount : Integer = 5;
          const maxCount : Integer = 20 );
        class function AccessInstance( Request : Integer;
          const minCount : Integer = 5; const maxCount : Integer = 20 )
          : ThreadPool;
      public
        constructor Create; { 构造函数}
        destructor destroy; override; { 析构函数}
        class function Instance( const minCount : Integer = 5;
          const maxCount : Integer = 20 ) : ThreadPool; { 实例化函数,客户端调用此函数}
        class procedure ReleaseInstance; { 释放资源函数,客户端调用此函数}
    
        procedure AddTask( task : TaskRec ); { 添加要执行的任务}
        function IsHaveTask : Boolean; { 是否有要执行的任务}
        procedure ExecuteTask; { 执行任务}
        function DoNextTask( executeThread : TExecuteThread ) : Boolean; { 执行下一任务}
        function IsSuspend( executeThread : TExecuteThread ) : Boolean; { 挂起线程}
    
        function GetPoolState : string; { 得到线程池状态}
    
      end;
    
    implementation
    
    {$J+}
    
    { MainUnit是为了测试引入的窗体单元,实际使用时候删除此单元和相关代码 }
    uses MainUnit;
    
    { -----------------------------------------------------------------------------}
    
    { 构造函数}
    constructor ThreadPool.Create;
    begin
      inherited Create;
      raise Exception.CreateFmt( 'Utils类只能通过Instance方法来创建和访问%s的实例!',
        [ ClassName ] );
    end;
    
    { 创建实例方法}
    constructor ThreadPool.CreateInstance( const minCount : Integer = 5;
      const maxCount : Integer = 20 );
    var
      i : Integer;
    begin
      inherited Create;
    
      { 需要在构造函数中初始化数据全部在此初始化}
    
    {$IFDEF MULTI_THREAD_WRITE_READ}
      { 创建多线程共享读独占写变量}
      Self.FMREWSync := TMREWSync.Create;
    {$ENDIF}
      Self.FTaskQueue := TQueue< TaskRec >.Create; { 实例化要执行的任务队列}
      Self.FTaskThreadList := TList< TExecuteThread >.Create; { 实例化执行任务线程List}
    
      Self.FThreadMin := minCount; { 最小线程数量}
      Self.FThreadMax := maxCount; { 最大线程数量}
    
      { 创建最小数量的线程}
      for i := 0 to minCount - 1 do
      begin
        { 把线程添加到线程List中}
        Self.FTaskThreadList.Add( TExecuteThread.Create( true ) );
      end;
    
    end;
    
    { 析构函数}
    destructor ThreadPool.destroy;
    begin
    
      { 需要析构前完成操作全部在此完成}
    
      Self.StopTaskAndFree; { 释放线程池资源}
    
    {$IFDEF MULTI_THREAD_WRITE_READ}
      { 释放多线程共享读独占写变量}
      Self.FMREWSync.Free;
    {$ENDIF}
      if AccessInstance( 0 ) = Self then
      begin
        AccessInstance( 2 );
      end;
    
      inherited destroy;
    end;
    
    class function ThreadPool.AccessInstance( Request : Integer;
      const minCount : Integer = 5; const maxCount : Integer = 20 ) : ThreadPool;
    const
      FInstance : ThreadPool = nil;
    begin
      {
        AccessInstance(0):不作任何处理,供释放实例对象时使用。
        AccessInstance(1):存在该实例时直接使用,不存在时则创建该实例。
        AccessInstance(2):返回一个空指针,用于重新设置实例。
      }
      case Request of
        0 :
          ;
        1 :
          if not Assigned( FInstance ) then
          begin
            FInstance := CreateInstance( minCount, maxCount );
          end;
        2 :
          FInstance := nil;
      else
        raise Exception.CreateFmt( ' %d 是AccessInstance()中的非法调用参数。', [ Request ] );
      end;
      Result := FInstance;
    end;
    
    { 得到类实例}
    class function ThreadPool.Instance( const minCount : Integer = 5;
      const maxCount : Integer = 20 ) : ThreadPool;
    begin
      { 返回实例}
      Result := AccessInstance( 1, minCount, maxCount );
    end;
    
    { 释放资源}
    class procedure ThreadPool.ReleaseInstance;
    begin
      AccessInstance( 0 ).Free;
    end;
    
    { ---- 类函数结束 ---- }
    
    procedure ThreadPool.StopTaskAndFree;
    var
      whileCount : Integer; { while循环计数变量}
      taskThread : TExecuteThread;
    begin
      { 1,释放线程List}
      try
        Self.BeginWrite;
    
        whileCount := 0; { while循环计数默认值为0}
        while whileCount < Self.FTaskThreadList.count do
        begin
          taskThread := Self.FTaskThreadList.Items[ whileCount ]; { 得到工作线程}
          Self.FTaskThreadList.Delete( whileCount ); { 从线程列表中删除线程}
          taskThread.Terminate; { 终止线程}
    
          Inc( whileCount ); { while循环计数递增}
        end;
    
      finally
        Self.EndWrite;
        Self.FTaskThreadList.Free; { 释放线程List}
      end;
    
      { 2,释放任务队列}
      Self.FTaskQueue.Clear;
      Self.FTaskQueue.Free;
    
    end;
    
    { 独占写开始}
    procedure ThreadPool.BeginWrite;
    begin
    {$IFDEF MULTI_THREAD_WRITE_READ}
      Self.FMREWSync.BeginWrite;
    {$ENDIF}
    end;
    
    { 独占写结束}
    procedure ThreadPool.EndWrite;
    begin
    {$IFDEF MULTI_THREAD_WRITE_READ}
      Self.FMREWSync.EndWrite;
    {$ENDIF}
    end;
    
    { 共享读开始}
    procedure ThreadPool.BeginRead;
    begin
    {$IFDEF MULTI_THREAD_WRITE_READ}
      Self.FMREWSync.BeginRead;
    {$ENDIF}
    end;
    
    { 共享读结束}
    procedure ThreadPool.EndRead;
    begin
    {$IFDEF MULTI_THREAD_WRITE_READ}
      Self.FMREWSync.EndRead;
    {$ENDIF}
    end;
    
    { 给线程池添加任务}
    procedure ThreadPool.AddTask( task : TaskRec );
    begin
    
      { 添加任务到线程池中}
      try
        Self.BeginWrite;
        Self.FTaskQueue.Enqueue( task ); { 把要执行任务加入任务队列}
      finally
        Self.EndWrite;
      end;
    
    end;
    
    { 是否有要执行的任务}
    function ThreadPool.IsHaveTask : Boolean;
    var
      temp : Boolean;
    begin
    
      temp := false;
    
      try
        Self.BeginRead;
    
        { 判断有要执行的任务}
        if Self.FTaskQueue.count > 0 then
        begin
          temp := true;
        end;
      finally
        Self.EndRead;
      end;
    
      Result := temp;
    end;
    
    { 执行任务}
    procedure ThreadPool.ExecuteTask;
    var
      whileCount : Integer; { while循环计数变量}
      isCanCreateThread : Boolean; { 是否可以创建新线程}
      curThread : TExecuteThread;
    begin
    
      { 在主界面memo中显示信息}
      Form1.log( '开始执行任务' ); { 测试使用,正式使用删除}
    
      if Self.IsHaveTask then
      begin
        { 1,判断是否有可以执行任务线程,如果有直接让线程执行}
        try
          Self.BeginRead;
    
          whileCount := 0; { while循环计数变量默认值为0}
          while whileCount < Self.FTaskThreadList.count do
          begin
    
            { 判断当前线程为挂起状态}
            if Self.FTaskThreadList.Items[ whileCount ].Suspended then
            begin
              Self.FTaskThreadList.Items[ whileCount ].Resume; { 唤醒挂起线程}
            end;
    
            Inc( whileCount ); { while循环计数递增}
    
          end;
    
        finally
          Self.EndRead;
    
          { 判断有要执行的任务}
          if Self.IsHaveTask then
          begin
    
            { 是否可以创建新线程默认值为false}
            isCanCreateThread := false;
    
            try
              Self.BeginRead;
    
              { 判断当前线程总数小于最大线程数量}
              if Self.FTaskThreadList.count < Self.FThreadMax then
              begin
                isCanCreateThread := true;
                {/ /是否可以创建新线程为true}
              end;
    
            finally
              Self.EndRead;
    
              { 判断可以创建新线程}
              if isCanCreateThread then
              begin
    
                while Self.FTaskThreadList.count < Self.FThreadMax do
                begin
                  { 创建新线程}
                  curThread := TExecuteThread.Create( true );
    
                  try
                    Self.BeginWrite;
                    { 把新线程加入线程List}
                    Self.FTaskThreadList.Add( curThread );
                  finally
                    Self.EndWrite;
                  end;
    
                  curThread.Resume;
                end;
    
              end;
    
            end;
    
          end;
    
        end;
      end;
    
    end;
    
    { 执行下一任务}
    function ThreadPool.DoNextTask( executeThread : TExecuteThread ) : Boolean;
    var
      isDoNextTask : Boolean; { 是否执行下一任务}
      nextTaskRec : TaskRec; { 下一任务结构}
      temp : Boolean;
    begin
    
      temp := false; { 返回布尔值默认值为false}
    
      try
    
        isDoNextTask := false; { 是否执行下一任务默认值为false}
    
        Self.BeginWrite;
    
        { 判断有要执行的任务}
        if Self.FTaskQueue.count > 0 then
        begin
          nextTaskRec := Self.FTaskQueue.Dequeue;
          isDoNextTask := true; { 是否执行任务为true}
          temp := true; { 返回布尔值为true}
        end;
    
      finally
        Self.EndWrite;
    
        { 判断执行下一任务}
        if isDoNextTask then
        begin
          executeThread.StartTask( nextTaskRec ); { 执行任务}
        end;
    
      end;
    
      Result := temp;
    end;
    
    { 判断线程是否需要挂起}
    function ThreadPool.IsSuspend( executeThread : TExecuteThread ) : Boolean;
    var
      temp : Boolean;
      isRemove : Boolean;
    begin
    
      temp := false;
    
      try
        Self.BeginRead;
    
        isRemove := false; { 是否从线程List中删除当前线程默认值为false}
    
        { 判断线程数量是否大于最小线程数量}
        if Self.FTaskThreadList.count > Self.FThreadMin then
        begin
          isRemove := true; { 是否从线程List中删除当前线程为true}
        end else begin
          temp := true; { 是否挂起为true}
        end;
      finally
        Self.EndRead;
    
        { 判断从线程List中删除当前线程}
        if isRemove then
        begin
          try
            Self.BeginWrite;
    
            { 从线程List中删除当前线程}
            Self.FTaskThreadList.Remove( executeThread );
          finally
            Self.EndWrite;
          end;
        end;
    
      end;
    
      Result := temp;
    
    end;
    
    { 得到线程池状态}
    function ThreadPool.GetPoolState : string;
    var
      temp : string; { 返回值变量}
      i : Integer; { 循环计数变量}
      curThread : TExecuteThread;
    begin
    
      temp := '线程状态:' + #13#10;;
    
      temp := temp + '最小线程数:' + inttostr( Self.FThreadMin ) + #13#10;
      temp := temp + '最大线程数:' + inttostr( Self.FThreadMax ) + #13#10;
    
      try
        Self.BeginRead;
    
        temp := temp + '线程总数:' + inttostr( Self.FTaskThreadList.count ) + #13#10;
        temp := temp + #13#10;
        temp := temp + '线程详细信息:' + #13#10;
        temp := temp + #13#10;
    
        for i := 0 to Self.FTaskThreadList.count - 1 do
        begin
          curThread := Self.FTaskThreadList.Items[ i ];
          temp := temp + '线程-' + inttostr( i + 1 ) + #13#10;
          temp := temp + '线程编号:' + inttostr( curThread.ThreadID ) + #13#10;
    
          { 是否挂起}
          if curThread.Suspended then
          begin
            temp := temp + '是否挂起: True' + #13#10;
          end else begin
            temp := temp + '是否挂起: False' + #13#10;
          end;
    
          { 是否可以执行任务}
          if curThread.FIsCanTask then
          begin
            temp := temp + '是否可以执行: True' + #13#10;
          end else begin
            temp := temp + '是否可以执行: False' + #13#10;
          end;
    
          { 是否同步执行任务}
          if curThread.FIsSynchronize then
          begin
            temp := temp + '是否同步执行: True' + #13#10;
          end else begin
            temp := temp + '是否同步执行: False' + #13#10;
          end;
    
          temp := temp + #13#10;
        end;
    
      finally
        Self.EndRead;
      end;
    
      Result := Trim( temp );
    end;
    
    { -----------------------------------------------------------------------------}
    
    { 执行任务线程构造函数}
    constructor TExecuteThread.Create( CreateSuspended : Boolean );
    begin
      inherited Create( CreateSuspended );
      FreeOnTerminate := true;
    
      Self.FIsCanTask := false; { 是否可以执行任务默认值为false}
      Self.FIsSynchronize := false; { 是否同步执行默认值为false}
    end;
    
    { 显示线程编号(测试使用)}
    procedure TExecuteThread.showThreadID;
    begin
      with Form1 do
      begin
        Memo1.Lines.Add( '停止执行任务线程编号:' + inttostr( Self.ThreadID ) )
      end;
    
    end;
    
    { 执行任务线程的主方法}
    procedure TExecuteThread.Execute;
    begin
      while not Terminated do
      begin
        if Terminated then
        begin
          Break;
        end;
    
        { 判断可以执行任务}
        if Self.FIsCanTask then
        begin
          Self.FProc( ); { 执行任务}
        end;
    
        { 判断不执行任务}
        if ThreadPool.Instance.DoNextTask( Self ) = false then
        begin
    
          { 显示执行任务线程编号}
          Synchronize( Self.showThreadID ); { 测试使用,正式使用删除}
    
          { 判断挂起当前线程}
          if ThreadPool.Instance.IsSuspend( Self ) then
          begin
            Self.Suspend; { 挂起}
          end
          else { 不挂起则终止当前线程}
          begin
            Self.Terminate; { 终止}
          end;
        end;
    
        { 使界面有反应}
        Application.ProcessMessages;
    
      end;
    end;
    
    { 设置要执行的任务}
    procedure TExecuteThread.StartTask( task : TaskRec );
    begin
      Self.FProc := task.TaskProc; { 设置要执行的任务}
      Self.FIsSynchronize := task.isSynchronize; { 设置是否同步执行}
      Self.FIsCanTask := true; { 设置是否可以执行任务为true}
    end;
    
    end.

    演示例子代码:

    unit MainUnit;
    
    interface
    
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
      System.Classes, Vcl.Graphics, System.DateUtils,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
    
    type
      TForm1 = class( TForm )
        Button1 : TButton;
        Memo1 : TMemo;
        Button2 : TButton;
        Button3 : TButton;
        Button7 : TButton;
        teskCountEdt : TEdit;
        Button8 : TButton;
        useTimeLab : TLabel;
        Label1 : TLabel;
        procedure Button1Click( Sender : TObject );
        procedure Button7Click( Sender : TObject );
        procedure Button3Click( Sender : TObject );
        procedure FormDestroy( Sender : TObject );
        procedure Button2Click( Sender : TObject );
        procedure Button8Click( Sender : TObject );
      private
        { Private declarations }
      public
        { Public declarations }
        procedure log( lgoInfo : string ); {  log方法 }
      end;
    
    var
      Form1 : TForm1;
    
      repeatCount : Integer = 0;
    
      startTime : TDateTime; {  开始时间 }
      useTime : Double; {  用时 }
    
    implementation
    
    {$R *.dfm}
    
    uses ThreadPoolUint;
    
    procedure TaskFun;
    var
      count : Integer;
    begin
    
      {  with Form1 do }
      {  begin }
      
      {  inc(repeatCount); }
      
      {  Memo1.Lines.Add(FormatDateTime('yyyy-mm-dd hh:mm:ss', Now) + }
      {  ' repeat count-' + IntToStr(repeatCount)); }
      
      {  count := 50000; }
      
      {  while count > 0 do }
      {  begin }
      {  Dec(count); }
      {  end; }
      
      {  end; }
    
      count := 0;
      while count < 100000 do
      begin
        inc( count );
      end;
    
    end;
    
    procedure TForm1.Button1Click( Sender : TObject );
    begin
      ThreadPool.Instance( 5, 20 );
      self.log( '线程池创建了' );
    end;
    
    procedure TForm1.Button2Click( Sender : TObject );
    var
      task : TaskRec;
      I : Integer;
      timeStr : string;
      posInt : Integer;
    begin
    
      startTime := Now;
      useTimeLab.Caption := '0';
    
      {  演示代码开始----------------------- }
    
      {  循环添加要执行的任务 }
    
      {  1,添加要执行任务 }
      for I := 0 to StrToInt( teskCountEdt.Text ) - 1 do
      begin
    
        {  执行任务记录 }
        task.isSynchronize := false;
        task.TaskProc := TaskFun;
    
        {  添加要执行的任务 }
        ThreadPool.Instance.AddTask( task );
      end;
    
      {  2,让线程池执行任务 }
      ThreadPool.Instance.ExecuteTask;
    
      {  演示代码结束----------------------- }
    
      useTime := MilliSecondSpan( startTime, Now );
      timeStr := FloatToStr( useTime );
      posInt := Pos( '.', timeStr );
      Delete( timeStr, posInt, Length( timeStr ) - ( posInt - 1 ) );
      useTimeLab.Caption := '共用时: ' + timeStr + ' 毫秒';
    
    end;
    
    procedure TForm1.Button3Click( Sender : TObject );
    begin
      self.log( ThreadPool.Instance.GetPoolState ); {  显示线程池状态 }
    end;
    
    procedure TForm1.Button7Click( Sender : TObject );
    begin
      ThreadPool.ReleaseInstance;
      self.log( '线程池释放了' );
    end;
    
    procedure TForm1.Button8Click( Sender : TObject );
    begin
      Memo1.Clear;
      repeatCount := 0;
      useTimeLab.Caption := '0';
    end;
    
    procedure TForm1.FormDestroy( Sender : TObject );
    begin
      ThreadPool.ReleaseInstance;
    end;
    
    procedure TForm1.log( lgoInfo : string );
    begin
      Memo1.Lines.Add( '' );
      Memo1.Lines.Add( FormatDateTime( 'yyyy-mm-dd hh:mm:ss', Now ) + ' ' +
        trim( lgoInfo ) )
    end;
    
    end.

    调用线程池的代码是:

    //1,定义一个要执行任务的结构

    task.isSynchronize := false;//是否同步执行

    task.TaskProc := TaskFun;//要执行任务方法

    // 2,向线程池添加要执行的任务

    ThreadPool.Instance.AddTask(task);

    // 3,让线程池执行任务

    ThreadPool.Instance.ExecuteTask;

    如果您有任何建议,请联系:sunylat@gmail.com QQ:14667479

  • 相关阅读:
    线程学习笔记(一)
    进程间通信
    管道通信操作
    在程序中执行shell命令
    进程控制(一)
    Makefile文件学习总结
    进程学习笔记
    C#不安全代码和指针
    Unity3D ShaderLab 修改渲染队列进行深度排序
    Unity3D ShaderLab 透明裁剪着色器
  • 原文地址:https://www.cnblogs.com/shangdawei/p/4019045.html
Copyright © 2020-2023  润新知