zoukankan      html  css  js  c++  java
  • [转载]Delphi线程池(Delphi2009以上版本适用)

    在网上查找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

  • 相关阅读:
    PHP邮件群发程序
    特牛的PHP分页
    短信平台PHP代码一点通
    PHP工厂模式的好处
    PHP单例模式经典讲解
    php excel类 ,phpExcel使用方法介绍
    php5魔术函数、魔术常量
    PHP设计模式漫谈之工厂模式
    PHP跨站刷票代码
    PHP类的静态(static)方法和静态(static)变量
  • 原文地址:https://www.cnblogs.com/luckForever/p/7255135.html
Copyright © 2011-2022 走看看