delphi线程池【转】

  1. [code=Delphi(Pascal)]
  2. unit uThreadPool;
  3. {  aPool.AddRequest(TMyRequest.Create(RequestParam1, RequestParam2, ...)); }
  4. interface
  5. uses
  6.   Windows,
  7.   Classes;
  8. // 是否记录日志
  9. // {$DEFINE NOLOGS}
  10. type
  11.   TCriticalSection = class(TObject)
  12.   protected
  13.     FSection: TRTLCriticalSection;
  14.   public
  15.     constructor Create;
  16.     destructor Destroy; override;
  17.     // 进入临界区
  18.     procedure Enter;
  19.     // 离开临界区
  20.     procedure Leave;
  21.     // 尝试进入
  22.     function TryEnter: Boolean;
  23.   end;
  24. type
  25.   // 储存请求数据的基本类
  26.   TWorkItem = class(TObject)
  27.   public
  28.     // 是否有重复任务
  29.     function IsTheSame(DataObj: TWorkItem): Boolean; virtual;
  30.     // 如果 NOLOGS 被定义,则禁用。
  31.     function TextForLog: string; virtual;
  32.   end;
  33. type
  34.   TThreadsPool = class;
  35.   //线程状态
  36.   TThreadState = (tcsInitializing, tcsWaiting, tcsGetting, tcsProcessing,
  37.     tcsProcessed, tcsTerminating, tcsCheckingDown);
  38.   // 工作线程仅用于线程池内, 不要直接创建并调用它。
  39.   TProcessorThread = class(TThread)
  40.   *******
  41.     // 创建线程时临时的Event对象, 阻塞线程直到初始化完成
  42.     hInitFinished: THandle;
  43.     // 初始化出错信息
  44.     sInitError: string;
  45.     // 记录日志
  46.     procedure WriteLog(const Str: string; Level: Integer = 0);
  47.   protected
  48.     // 线程临界区同步对像
  49.     csProcessingDataObject: TCriticalSection;
  50.     // 平均处理时间
  51.     FAverageProcessing: Integer;
  52.     // 等待请求的平均时间
  53.     FAverageWaitingTime: Integer;
  54.     // 本线程实例的运行状态
  55.     FCurState: TThreadState;
  56.     // 本线程实例所附属的线程池
  57.     FPool: TThreadsPool;
  58.     // 当前处理的数据对像。
  59.     FProcessingDataObject: TWorkItem;
  60.     // 线程停止 Event, TProcessorThread.Terminate 中开绿灯
  61.     hThreadTerminated: THandle;
  62.     uProcessingStart: DWORD;
  63.     // 开始等待的时间, 通过 GetTickCount 取得。
  64.     uWaitingStart: DWORD;
  65.     // 计算平均工作时间
  66.     function AverageProcessingTime: DWORD;
  67.     // 计算平均等待时间
  68.     function AverageWaitingTime: DWORD;
  69.     procedure Execute; override;
  70.     function IamCurrentlyProcess(DataObj: TWorkItem): Boolean;
  71.     // 转换枚举类型的线程状态为字串类型
  72.     function InfoText: string;
  73.     // 线程是否长时间处理同一个请求?(已死掉?)
  74.     function IsDead: Boolean;
  75.     // 线程是否已完成当成任务
  76.     function isFinished: Boolean;
  77.     // 线程是否处于空闲状态
  78.     function isIdle: Boolean;
  79.     // 平均值校正计算。
  80.     function NewAverage(OldAvg, NewVal: Integer): Integer;
  81.   public
  82.     Tag: Integer;
  83.     constructor Create(APool: TThreadsPool);
  84.     destructor Destroy; override;
  85.     procedure Terminate;
  86.   end;
  87.   // 线程初始化时触发的事件
  88.   TProcessorThreadInitializing = procedure(Sender: TThreadsPool; aThread:
  89.     TProcessorThread) of object;
  90.   // 线程结束时触发的事件
  91.   TProcessorThreadFinalizing = procedure(Sender: TThreadsPool; aThread:
  92.     TProcessorThread) of object;
  93.   // 线程处理请求时触发的事件
  94.   TProcessRequest = procedure(Sender: TThreadsPool; WorkItem: TWorkItem;
  95.     aThread: TProcessorThread) of object;
  96.   TEmptyKind = (
  97.     ekQueueEmpty, //任务被取空后
  98.     ekProcessingFinished // 最后一个任务处理完毕后
  99.     );
  100.   // 任务队列空时触发的事件
  101.   TQueueEmpty = procedure(Sender: TThreadsPool; EmptyKind: TEmptyKind) of
  102.     object;
  103.   TThreadsPool = class(TComponent)
  104.   *******
  105.     csQueueManagment: TCriticalSection;
  106.     csThreadManagment: TCriticalSection;
  107.     FProcessRequest: TProcessRequest;
  108.     FQueue: TList;
  109.     FQueueEmpty: TQueueEmpty;
  110.     // 线程超时阀值
  111.     FThreadDeadTimeout: DWORD;
  112.     FThreadFinalizing: TProcessorThreadFinalizing;
  113.     FThreadInitializing: TProcessorThreadInitializing;
  114.     // 工作中的线程
  115.     FThreads: TList;
  116.     // 执行了 terminat 发送退出指令, 正在结束的线程.
  117.     FThreadsKilling: TList;
  118.     // 最少, 最大线程数
  119.     FThreadsMax: Integer;
  120.     // 最少, 最大线程数
  121.     FThreadsMin: Integer;
  122.     // 池平均等待时间
  123.     function PoolAverageWaitingTime: Integer;
  124.     procedure WriteLog(const Str: string; Level: Integer = 0);
  125.   protected
  126.     FLastGetPoint: Integer;
  127.     // Semaphore, 统计任务队列
  128.     hSemRequestCount: THandle;
  129.     // Waitable timer. 每30触发一次的时间量同步
  130.     hTimCheckPoolDown: THandle;
  131.     // 线程池停机(检查并清除空闲线程和死线程)
  132.     procedure CheckPoolDown;
  133.     // 清除死线程,并补充不足的工作线程
  134.     procedure CheckThreadsForGrow;
  135.     procedure DoProcessed;
  136.     procedure DoProcessRequest(aDataObj: TWorkItem; aThread: TProcessorThread);
  137.       virtual;
  138.     procedure DoQueueEmpty(EmptyKind: TEmptyKind); virtual;
  139.     procedure DoThreadFinalizing(aThread: TProcessorThread); virtual;
  140.     // 执行事件
  141.     procedure DoThreadInitializing(aThread: TProcessorThread); virtual;
  142.     // 释放 FThreadsKilling 列表中的线程
  143.     procedure FreeFinishedThreads;
  144.     // 申请任务
  145.     procedure GetRequest(out Request: TWorkItem);
  146.     // 清除死线程
  147.     procedure KillDeadThreads;
  148.   public
  149.     constructor Create(AOwner: TComponent); override;
  150.     destructor Destroy; override;
  151.     // 就进行任务是否重复的检查, 检查发现重复就返回 False
  152.     function AddRequest(aDataObject: TWorkItem; CheckForDoubles: Boolean =
  153.       False): Boolean; overload;
  154.     // 转换枚举类型的线程状态为字串类型
  155.     function InfoText: string;
  156.   published
  157.     // 线程处理任务时触发的事件
  158.     property OnProcessRequest: TProcessRequest read FProcessRequest write
  159.       FProcessRequest;
  160.     // 任务列表为空时解发的事件
  161.     property OnQueueEmpty: TQueueEmpty read FQueueEmpty write FQueueEmpty;
  162.     // 线程结束时触发的事件
  163.     property OnThreadFinalizing: TProcessorThreadFinalizing read
  164.       FThreadFinalizing write FThreadFinalizing;
  165.     // 线程初始化时触发的事件
  166.     property OnThreadInitializing: TProcessorThreadInitializing read
  167.       FThreadInitializing write FThreadInitializing;
  168.     // 线程超时值(毫秒), 如果处理超时,将视为死线程
  169.     property ThreadDeadTimeout: DWORD read FThreadDeadTimeout write
  170.       FThreadDeadTimeout default 0;
  171.     // 最大线程数
  172.     property ThreadsMax: Integer read FThreadsMax write FThreadsMax default 1;
  173.     // 最小线程数
  174.     property ThreadsMin: Integer read FThreadsMin write FThreadsMin default 0;
  175.   end;
  176. type
  177.   //日志记志函数
  178.   TLogWriteProc = procedure(
  179.     const Str: string; //日志
  180.     LogID: Integer = 0;
  181.     Level: Integer = 0 //Level = 0 - 跟踪信息, 10 - 致命错误
  182.     );
  183. var
  184.   WriteLog: TLogWriteProc; // 如果存在实例就写日志
  185. implementation
  186. uses
  187.   SysUtils;
  188. // 储存请求数据的基本类
  189. {
  190. ********************************** TWorkItem ***********************************
  191. }
  192. function TWorkItem.IsTheSame(DataObj: TWorkItem): Boolean;
  193. begin
  194.   Result := False;
  195. end; { TWorkItem.IsTheSame }
  196. function TWorkItem.TextForLog: string;
  197. begin
  198.   Result := 'Request';
  199. end; { TWorkItem.TextForLog }
  200. {
  201. ********************************* TThreadsPool *********************************
  202. }
  203. constructor TThreadsPool.Create(AOwner: TComponent);
  204. var
  205.   DueTo: Int64;
  206. begin
  207. {$IFNDEF NOLOGS}
  208.   WriteLog('创建线程池', 5);
  209. {$ENDIF}
  210.   inherited;
  211.   csQueueManagment := TCriticalSection.Create;
  212.   FQueue := TList.Create;
  213.   csThreadManagment := TCriticalSection.Create;
  214.   FThreads := TList.Create;
  215.   FThreadsKilling := TList.Create;
  216.   FThreadsMin := 0;
  217.   FThreadsMax := 1;
  218.   FThreadDeadTimeout := 0;
  219.   FLastGetPoint := 0;
  220.   //
  221.   hSemRequestCount := CreateSemaphore(nil, 0, $7FFFFFFF, nil);
  222.   DueTo := -1;
  223.   //可等待的定时器(只用于Window NT4或更高)
  224.   hTimCheckPoolDown := CreateWaitableTimer(nil, False, nil);
  225.   if hTimCheckPoolDown = 0 then // Win9x不支持
  226.     // In Win9x number of thread will be never decrised
  227.     hTimCheckPoolDown := CreateEvent(nil, False, False, nil)
  228.   else
  229.     SetWaitableTimer(hTimCheckPoolDown, DueTo, 30000, nil, nil, False);
  230. end; { TThreadsPool.Create }
  231. destructor TThreadsPool.Destroy;
  232. var
  233.   n, i: Integer;
  234.   Handles: array of THandle;
  235. begin
  236. {$IFNDEF NOLOGS}
  237.   WriteLog('线程池销毁', 5);
  238. {$ENDIF}
  239.   csThreadManagment.Enter;
  240.   SetLength(Handles, FThreads.Count);
  241.   n := 0;
  242.   for i := 0 to FThreads.Count - 1 do
  243.     if FThreads[i] <> nil then
  244.     begin
  245.       Handles[n] := TProcessorThread(FThreads[i]).Handle;
  246.       TProcessorThread(FThreads[i]).Terminate;
  247.       Inc(n);
  248.     end;
  249.   csThreadManagment.Leave;  // lixiaoyu 添加于 2009.1.6,如没有此行代码无法成功释放正在执行中的工作者线程,死锁。
  250.   WaitForMultipleObjects(n, @Handles[0], True, 30000);  // 等待工作者线程执行终止  lixiaoyu 注释于 2009.1.6
  251.   csThreadManagment.Enter;  // lixiaoyu 添加于 2009.1.6 再次进入锁定,并释放资源
  252.   for i := 0 to FThreads.Count - 1 do
  253.     TProcessorThread(FThreads[i]).Free;
  254.   FThreads.Free;
  255.   FThreadsKilling.Free;
  256.   csThreadManagment.Free;
  257.   csQueueManagment.Enter;
  258.   for i := FQueue.Count - 1 downto 0 do
  259.     TObject(FQueue[i]).Free;
  260.   FQueue.Free;
  261.   csQueueManagment.Free;
  262.   CloseHandle(hSemRequestCount);
  263.   CloseHandle(hTimCheckPoolDown);
  264.   inherited;
  265. end; { TThreadsPool.Destroy }
  266. function TThreadsPool.AddRequest(aDataObject: TWorkItem; CheckForDoubles:
  267.   Boolean = False): Boolean;
  268. var
  269.   i: Integer;
  270. begin
  271. {$IFNDEF NOLOGS}
  272.   WriteLog('AddRequest(' + aDataObject.TextForLog + ')', 2);
  273. {$ENDIF}
  274.   Result := False;
  275.   csQueueManagment.Enter;
  276.   try
  277.     // 如果 CheckForDoubles = TRUE
  278.     // 则进行任务是否重复的检查
  279.     if CheckForDoubles then
  280.       for i := 0 to FQueue.Count - 1 do
  281.         if (FQueue[i] <> nil)
  282.           and aDataObject.IsTheSame(TWorkItem(FQueue[i])) then
  283.           Exit; // 发现有相同的任务
  284.     csThreadManagment.Enter;
  285.     try
  286.       // 清除死线程,并补充不足的工作线程
  287.       CheckThreadsForGrow;
  288.       // 如果 CheckForDoubles = TRUE
  289.       // 则检查是否有相同的任务正在处理中
  290.       if CheckForDoubles then
  291.         for i := 0 to FThreads.Count - 1 do
  292.           if TProcessorThread(FThreads[i]).IamCurrentlyProcess(aDataObject) then
  293.             Exit; // 发现有相同的任务
  294.     finally
  295.       csThreadManagment.Leave;
  296.     end;
  297.     //将任务加入队列
  298.     FQueue.Add(aDataObject);
  299.     //释放一个同步信号量
  300.     ReleaseSemaphore(hSemRequestCount, 1, nil);
  301. {$IFNDEF NOLOGS}
  302.     WriteLog('释放一个同步信号量)', 1);
  303. {$ENDIF}
  304.     Result := True;
  305.   finally
  306.     csQueueManagment.Leave;
  307.   end;
  308. {$IFNDEF NOLOGS}
  309.   //调试信息
  310.   WriteLog('增加一个任务(' + aDataObject.TextForLog + ')', 1);
  311. {$ENDIF}
  312. end; { TThreadsPool.AddRequest }
  313. {
  314. 函 数 名:TThreadsPool.CheckPoolDown
  315. 功能描述:线程池停机(检查并清除空闲线程和死线程)
  316. 输入参数:无
  317. 返 回 值: 无
  318. 创建日期:2006.10.22 11:31
  319. 修改日期:2006.
  320. 作    者:Kook
  321. 附加说明:
  322. }
  323. procedure TThreadsPool.CheckPoolDown;
  324. var
  325.   i: Integer;
  326. begin
  327. {$IFNDEF NOLOGS}
  328.   WriteLog('TThreadsPool.CheckPoolDown', 1);
  329. {$ENDIF}
  330.   csThreadManagment.Enter;
  331.   try
  332. {$IFNDEF NOLOGS}
  333.     WriteLog(InfoText, 2);
  334. {$ENDIF}
  335.     // 清除死线程
  336.     KillDeadThreads;
  337.     // 释放 FThreadsKilling 列表中的线程
  338.     FreeFinishedThreads;
  339.     // 如果线程空闲,就终止它
  340.     for i := FThreads.Count - 1 downto FThreadsMin do
  341.       if TProcessorThread(FThreads[i]).isIdle then
  342.       begin
  343.         //发出终止命令
  344.         TProcessorThread(FThreads[i]).Terminate;
  345.         //加入待清除队列
  346.         FThreadsKilling.Add(FThreads[i]);
  347.         //从工作队列中除名
  348.         FThreads.Delete(i);
  349.         //todo: ??
  350.         Break;
  351.       end;
  352.   finally
  353.     csThreadManagment.Leave;
  354.   end;
  355. end; { TThreadsPool.CheckPoolDown }
  356. {
  357. 函 数 名:TThreadsPool.CheckThreadsForGrow
  358. 功能描述:清除死线程,并补充不足的工作线程
  359. 输入参数:无
  360. 返 回 值: 无
  361. 创建日期:2006.10.22 11:31
  362. 修改日期:2006.
  363. 作    者:Kook
  364. 附加说明:
  365. }
  366. procedure TThreadsPool.CheckThreadsForGrow;
  367. var
  368.   AvgWait: Integer;
  369.   i: Integer;
  370. begin
  371.   {
  372.     New thread created if:
  373.     新建线程的条件:
  374.       1. 工作线程数小于最小线程数
  375.       2. 工作线程数小于最大线程数 and 线程池平均等待时间 < 100ms(系统忙)
  376.       3. 任务大于工作线程数的4倍
  377.   }
  378.   csThreadManagment.Enter;
  379.   try
  380.     KillDeadThreads;
  381.     if FThreads.Count < FThreadsMin then
  382.     begin
  383. {$IFNDEF NOLOGS}
  384.       WriteLog('工作线程数小于最小线程数', 4);
  385. {$ENDIF}
  386.       for i := FThreads.Count to FThreadsMin - 1 do
  387.       try
  388.         FThreads.Add(TProcessorThread.Create(Self));
  389.       except
  390.         on e: Exception do
  391.           WriteLog(
  392.             'TProcessorThread.Create raise: ' + e.ClassName + #13#10#9'Message: '
  393.             + e.Message,
  394.             9
  395.             );
  396.       end
  397.     end
  398.     else if FThreads.Count < FThreadsMax then
  399.     begin
  400. {$IFNDEF NOLOGS}
  401.       WriteLog('工作线程数小于最大线程数 and 线程池平均等待时间 < 100ms', 3);
  402. {$ENDIF}
  403.       AvgWait := PoolAverageWaitingTime;
  404. {$IFNDEF NOLOGS}
  405.       WriteLog(Format(
  406.         'FThreads.Count (%d)<FThreadsMax(%d), AvgWait=%d',
  407.         [FThreads.Count, FThreadsMax, AvgWait]),
  408.         4
  409.         );
  410. {$ENDIF}
  411.       if AvgWait < 100 then
  412.       try
  413.         FThreads.Add(TProcessorThread.Create(Self));
  414.       except
  415.         on e: Exception do
  416.           WriteLog(
  417.             'TProcessorThread.Create raise: ' + e.ClassName +
  418.             #13#10#9'Message: ' + e.Message,
  419.             9
  420.             );
  421.       end;
  422.     end;
  423.   finally
  424.     csThreadManagment.Leave;
  425.   end;
  426. end; { TThreadsPool.CheckThreadsForGrow }
  427. procedure TThreadsPool.DoProcessed;
  428. var
  429.   i: Integer;
  430. begin
  431.   if (FLastGetPoint < FQueue.Count) then
  432.     Exit;
  433.   csThreadManagment.Enter;
  434.   try
  435.     for i := 0 to FThreads.Count - 1 do
  436.       if TProcessorThread(FThreads[i]).FCurState in [tcsProcessing] then
  437.         Exit;
  438.   finally
  439.     csThreadManagment.Leave;
  440.   end;
  441.   DoQueueEmpty(ekProcessingFinished);
  442. end; { TThreadsPool.DoProcessed }
  443. procedure TThreadsPool.DoProcessRequest(aDataObj: TWorkItem; aThread:
  444.   TProcessorThread);
  445. begin
  446.   if Assigned(FProcessRequest) then
  447.     FProcessRequest(Self, aDataObj, aThread);
  448. end; { TThreadsPool.DoProcessRequest }
  449. procedure TThreadsPool.DoQueueEmpty(EmptyKind: TEmptyKind);
  450. begin
  451.   if Assigned(FQueueEmpty) then
  452.     FQueueEmpty(Self, EmptyKind);
  453. end; { TThreadsPool.DoQueueEmpty }
  454. procedure TThreadsPool.DoThreadFinalizing(aThread: TProcessorThread);
  455. begin
  456.   if Assigned(FThreadFinalizing) then
  457.     FThreadFinalizing(Self, aThread);
  458. end; { TThreadsPool.DoThreadFinalizing }
  459. procedure TThreadsPool.DoThreadInitializing(aThread: TProcessorThread);
  460. begin
  461.   if Assigned(FThreadInitializing) then
  462.     FThreadInitializing(Self, aThread);
  463. end; { TThreadsPool.DoThreadInitializing }
  464. {
  465. 函 数 名:TThreadsPool.FreeFinishedThreads
  466. 功能描述:释放 FThreadsKilling 列表中的线程
  467. 输入参数:无
  468. 返 回 值: 无
  469. 创建日期:2006.10.22 11:34
  470. 修改日期:2006.
  471. 作    者:Kook
  472. 附加说明:
  473. }
  474. procedure TThreadsPool.FreeFinishedThreads;
  475. var
  476.   i: Integer;
  477. begin
  478.   if csThreadManagment.TryEnter then
  479.   try
  480.     for i := FThreadsKilling.Count - 1 downto 0 do
  481.       if TProcessorThread(FThreadsKilling[i]).isFinished then
  482.       begin
  483.         TProcessorThread(FThreadsKilling[i]).Free;
  484.         FThreadsKilling.Delete(i);
  485.       end;
  486.   finally
  487.     csThreadManagment.Leave
  488.   end;
  489. end; { TThreadsPool.FreeFinishedThreads }
  490. {
  491. 函 数 名:TThreadsPool.GetRequest
  492. 功能描述:申请任务
  493. 输入参数:out Request: TRequestDataObject
  494. 返 回 值: 无
  495. 创建日期:2006.10.22 11:34
  496. 修改日期:2006.
  497. 作    者:Kook
  498. 附加说明:
  499. }
  500. procedure TThreadsPool.GetRequest(out Request: TWorkItem);
  501. begin
  502. {$IFNDEF NOLOGS}
  503.   WriteLog('申请任务', 2);
  504. {$ENDIF}
  505.   csQueueManagment.Enter;
  506.   try
  507.     //跳过空的队列元素
  508.     while (FLastGetPoint < FQueue.Count) and (FQueue[FLastGetPoint] = nil) do
  509.       Inc(FLastGetPoint);
  510.     Assert(FLastGetPoint < FQueue.Count);
  511.     //压缩队列,清除空元素
  512.     if (FQueue.Count > 127) and (FLastGetPoint >= (3 * FQueue.Count) div 4) then
  513.     begin
  514. {$IFNDEF NOLOGS}
  515.       WriteLog('FQueue.Pack', 1);
  516. {$ENDIF}
  517.       FQueue.Pack;
  518.       FLastGetPoint := 0;
  519.     end;
  520.     Request := TWorkItem(FQueue[FLastGetPoint]);
  521.     FQueue[FLastGetPoint] := nil;
  522.     inc(FLastGetPoint);
  523.     if (FLastGetPoint = FQueue.Count) then //如果队列中无任务
  524.     begin
  525.       DoQueueEmpty(ekQueueEmpty);
  526.       FQueue.Clear;
  527.       FLastGetPoint := 0;
  528.     end;
  529.   finally
  530.     csQueueManagment.Leave;
  531.   end;
  532. end; { TThreadsPool.GetRequest }
  533. function TThreadsPool.InfoText: string;
  534. begin
  535.   Result := '';
  536.   //end;
  537.   //{$ELSE}
  538.   //var
  539.   //  i: Integer;
  540.   //begin
  541.   //  csQueueManagment.Enter;
  542.   //  csThreadManagment.Enter;
  543.   //  try
  544.   //    if (FThreads.Count = 0) and (FThreadsKilling.Count = 1) and
  545.   //      TProcessorThread(FThreadsKilling[0]).isFinished then
  546.   //      FreeFinishedThreads;
  547.   //
  548.   //    Result := Format(
  549.   //      'Pool thread: Min=%d, Max=%d, WorkingThreadsCount=%d, TerminatedThreadCount=%d, QueueLength=%d'#13#10,
  550.   //      [ThreadsMin, ThreadsMax, FThreads.Count, FThreadsKilling.Count,
  551.   //      FQueue.Count]
  552.   //        );
  553.   //    if FThreads.Count > 0 then
  554.   //      Result := Result + 'Working threads:'#13#10;
  555.   //    for i := 0 to FThreads.Count - 1 do
  556.   //      Result := Result + TProcessorThread(FThreads[i]).InfoText + #13#10;
  557.   //    if FThreadsKilling.Count > 0 then
  558.   //      Result := Result + 'Terminated threads:'#13#10;
  559.   //    for i := 0 to FThreadsKilling.Count - 1 do
  560.   //      Result := Result + TProcessorThread(FThreadsKilling[i]).InfoText + #13#10;
  561.   //  finally
  562.   //    csThreadManagment.Leave;
  563.   //    csQueueManagment.Leave;
  564.   //  end;
  565.   //end;
  566.   //{$ENDIF}
  567. end; { TThreadsPool.InfoText }
  568. {
  569. 函 数 名:TThreadsPool.KillDeadThreads
  570. 功能描述:清除死线程
  571. 输入参数:无
  572. 返 回 值: 无
  573. 创建日期:2006.10.22 11:32
  574. 修改日期:2006.
  575. 作    者:Kook
  576. 附加说明:
  577. }
  578. procedure TThreadsPool.KillDeadThreads;
  579. var
  580.   i: Integer;
  581. begin
  582.   // Check for dead threads
  583.   if csThreadManagment.TryEnter then
  584.   try
  585.     for i := 0 to FThreads.Count - 1 do
  586.       if TProcessorThread(FThreads[i]).IsDead then
  587.       begin
  588.         // Dead thread moverd to other list.
  589.         // New thread created to replace dead one
  590.         TProcessorThread(FThreads[i]).Terminate;
  591.         FThreadsKilling.Add(FThreads[i]);
  592.         try
  593.           FThreads[i] := TProcessorThread.Create(Self);
  594.         except
  595.           on e: Exception do
  596.           begin
  597.             FThreads[i] := nil;
  598. {$IFNDEF NOLOGS}
  599.             WriteLog(
  600.               'TProcessorThread.Create raise: ' + e.ClassName +
  601.               #13#10#9'Message: ' + e.Message,
  602.               9
  603.               );
  604. {$ENDIF}
  605.           end;
  606.         end;
  607.       end;
  608.   finally
  609.     csThreadManagment.Leave
  610.   end;
  611. end; { TThreadsPool.KillDeadThreads }
  612. function TThreadsPool.PoolAverageWaitingTime: Integer;
  613. var
  614.   i: Integer;
  615. begin
  616.   Result := 0;
  617.   if FThreads.Count > 0 then
  618.   begin
  619.     for i := 0 to FThreads.Count - 1 do
  620.       Inc(result, TProcessorThread(FThreads[i]).AverageWaitingTime);
  621.     Result := Result div FThreads.Count
  622.   end
  623.   else
  624.     Result := 1;
  625. end; { TThreadsPool.PoolAverageWaitingTime }
  626. procedure TThreadsPool.WriteLog(const Str: string; Level: Integer = 0);
  627. begin
  628. {$IFNDEF NOLOGS}
  629.   uThreadPool.WriteLog(Str, 0, Level);
  630. {$ENDIF}
  631. end; { TThreadsPool.WriteLog }
  632. // 工作线程仅用于线程池内, 不要直接创建并调用它。
  633. {
  634. ******************************* TProcessorThread *******************************
  635. }
  636. constructor TProcessorThread.Create(APool: TThreadsPool);
  637. begin
  638.   WriteLog('创建工作线程', 5);
  639.   inherited Create(True);
  640.   FPool := aPool;
  641.   FAverageWaitingTime := 1000;
  642.   FAverageProcessing := 3000;
  643.   sInitError := '';
  644.   {
  645.   各参数的意义如下:
  646.    
  647.   参数一:填上 nil 即可。
  648.   参数二:是否采用手动调整灯号。
  649.   参数三:灯号的起始状态,False 表示红灯。
  650.   参数四:Event 名称, 对象名称相同的话,会指向同一个对象,所以想要有两个Event对象,便要有两个不同的名称(这名称以字符串来存.为NIL的话系统每次会自己创建一个不同的名字,就是被次创建的都是新的EVENT)。
  651.   传回值:Event handle。
  652.   }
  653.   hInitFinished := CreateEvent(nil, True, False, nil);
  654.   hThreadTerminated := CreateEvent(nil, True, False, nil);
  655.   csProcessingDataObject := TCriticalSection.Create;
  656.   try
  657.     WriteLog('TProcessorThread.Create::Resume', 3);
  658.     Resume;
  659.     //阻塞, 等待初始化完成
  660.     WaitForSingleObject(hInitFinished, INFINITE);
  661.     if sInitError <> '' then
  662.       raise Exception.Create(sInitError);
  663.   finally
  664.     CloseHandle(hInitFinished);
  665.   end;
  666.   WriteLog('TProcessorThread.Create::Finished', 3);
  667. end; { TProcessorThread.Create }
  668. destructor TProcessorThread.Destroy;
  669. begin
  670.   WriteLog('工作线程销毁', 5);
  671.   CloseHandle(hThreadTerminated);
  672.   csProcessingDataObject.Free;
  673.   inherited;
  674. end; { TProcessorThread.Destroy }
  675. function TProcessorThread.AverageProcessingTime: DWORD;
  676. begin
  677.   if (FCurState in [tcsProcessing]) then
  678.     Result := NewAverage(FAverageProcessing, GetTickCount - uProcessingStart)
  679.   else
  680.     Result := FAverageProcessing
  681. end; { TProcessorThread.AverageProcessingTime }
  682. function TProcessorThread.AverageWaitingTime: DWORD;
  683. begin
  684.   if (FCurState in [tcsWaiting, tcsCheckingDown]) then
  685.     Result := NewAverage(FAverageWaitingTime, GetTickCount - uWaitingStart)
  686.   else
  687.     Result := FAverageWaitingTime
  688. end; { TProcessorThread.AverageWaitingTime }
  689. procedure TProcessorThread.Execute;
  690. type
  691.   THandleID = (hidTerminateThread, hidRequest, hidCheckPoolDown);
  692. var
  693.   WaitedTime: Integer;
  694.   Handles: array[THandleID] of THandle;
  695. begin
  696.   WriteLog('工作线程进常运行', 3);
  697.   //当前状态:初始化
  698.   FCurState := tcsInitializing;
  699.   try
  700.     //执行外部事件
  701.     FPool.DoThreadInitializing(Self);
  702.   except
  703.     on e: Exception do
  704.       sInitError := e.Message;
  705.   end;
  706.   //初始化完成,初始化Event绿灯
  707.   SetEvent(hInitFinished);
  708.   WriteLog('TProcessorThread.Execute::Initialized', 3);
  709.   //引用线程池的同步 Event
  710.   Handles[hidTerminateThread] := hThreadTerminated;
  711.   Handles[hidRequest] := FPool.hSemRequestCount;
  712.   Handles[hidCheckPoolDown] := FPool.hTimCheckPoolDown;
  713.   //时间戳,
  714.   //todo: 好像在线程中用 GetTickCount; 会不正常
  715.   uWaitingStart := GetTickCount;
  716.   //任务置空
  717.   FProcessingDataObject := nil;
  718.   //大巡环
  719.   while not terminated do
  720.   begin
  721.     //当前状态:等待
  722.     FCurState := tcsWaiting;
  723.     //阻塞线程,使线程休眠
  724.     case WaitForMultipleObjects(Length(Handles), @Handles, False, INFINITE) -
  725.       WAIT_OBJECT_0 of
  726.       WAIT_OBJECT_0 + ord(hidTerminateThread):
  727.         begin
  728.           WriteLog('TProcessorThread.Execute:: Terminate event signaled ', 5);
  729.           //当前状态:正在终止线程
  730.           FCurState := tcsTerminating;
  731.           //退出大巡环(结束线程)
  732.           Break;
  733.         end;
  734.       WAIT_OBJECT_0 + ord(hidRequest):
  735.         begin
  736.           WriteLog('TProcessorThread.Execute:: Request semaphore signaled ', 3);
  737.           //等待的时间
  738.           WaitedTime := GetTickCount - uWaitingStart;
  739.           //重新计算平均等待时间
  740.           FAverageWaitingTime := NewAverage(FAverageWaitingTime, WaitedTime);
  741.           //当前状态:申请任务
  742.           FCurState := tcsGetting;
  743.           //如果等待时间过短,则检查工作线程是否足够
  744.           if WaitedTime < 5 then
  745.             FPool.CheckThreadsForGrow;
  746.           //从线程池的任务队列中得到任务
  747.           FPool.GetRequest(FProcessingDataObject);
  748.           //开始处理的时间戳
  749.           uProcessingStart := GetTickCount;
  750.           //当前状态:执行任务
  751.           FCurState := tcsProcessing;
  752.           try
  753. {$IFNDEF NOLOGS}
  754.             WriteLog('Processing: ' + FProcessingDataObject.TextForLog, 2);
  755. {$ENDIF}
  756.             //执行任务
  757.             FPool.DoProcessRequest(FProcessingDataObject, Self);
  758.           except
  759.             on e: Exception do
  760.               WriteLog(
  761.                 'OnProcessRequest for ' + FProcessingDataObject.TextForLog +
  762.                 #13#10'raise Exception: ' + e.Message,
  763.                 8
  764.                 );
  765.           end;
  766.           //释放任务对象
  767.           csProcessingDataObject.Enter;
  768.           try
  769.             FProcessingDataObject.Free;
  770.             FProcessingDataObject := nil;
  771.           finally
  772.             csProcessingDataObject.Leave;
  773.           end;
  774.           //重新计算
  775.           FAverageProcessing := NewAverage(FAverageProcessing, GetTickCount -
  776.             uProcessingStart);
  777.           //当前状态:执行任务完毕
  778.           FCurState := tcsProcessed;
  779.           //执行线程外事件
  780.           FPool.DoProcessed;
  781.           uWaitingStart := GetTickCount;
  782.         end;
  783.       WAIT_OBJECT_0 + ord(hidCheckPoolDown):
  784.         begin
  785.           // !!! Never called under Win9x
  786.           WriteLog('TProcessorThread.Execute:: CheckPoolDown timer signaled ',
  787.             4);
  788.           //当前状态:线程池停机(检查并清除空闲线程和死线程)
  789.           FCurState := tcsCheckingDown;
  790.           FPool.CheckPoolDown;
  791.         end;
  792.     end;
  793.   end;
  794.   FCurState := tcsTerminating;
  795.   FPool.DoThreadFinalizing(Self);
  796. end; { TProcessorThread.Execute }
  797. function TProcessorThread.IamCurrentlyProcess(DataObj: TWorkItem): Boolean;
  798. begin
  799.   csProcessingDataObject.Enter;
  800.   try
  801.     Result := (FProcessingDataObject <> nil) and
  802.       DataObj.IsTheSame(FProcessingDataObject);
  803.   finally
  804.     csProcessingDataObject.Leave;
  805.   end;
  806. end; { TProcessorThread.IamCurrentlyProcess }
  807. function TProcessorThread.InfoText: string;
  808. const
  809.   ThreadStateNames: array[TThreadState] of string =
  810.   (
  811.     'tcsInitializing',
  812.     'tcsWaiting',
  813.     'tcsGetting',
  814.     'tcsProcessing',
  815.     'tcsProcessed',
  816.     'tcsTerminating',
  817.     'tcsCheckingDown'
  818.     );
  819. begin
  820. {$IFNDEF NOLOGS}
  821.   Result := Format(
  822.     '%5d: %15s, AverageWaitingTime=%6d, AverageProcessingTime=%6d',
  823.     [ThreadID, ThreadStateNames[FCurState], AverageWaitingTime,
  824.     AverageProcessingTime]
  825.       );
  826.   case FCurState of
  827.     tcsWaiting:
  828.       Result := Result + ', WaitingTime=' + IntToStr(GetTickCount -
  829.         uWaitingStart);
  830.     tcsProcessing:
  831.       Result := Result + ', ProcessingTime=' + IntToStr(GetTickCount -
  832.         uProcessingStart);
  833.   end;
  834.   csProcessingDataObject.Enter;
  835.   try
  836.     if FProcessingDataObject <> nil then
  837.       Result := Result + ' ' + FProcessingDataObject.TextForLog;
  838.   finally
  839.     csProcessingDataObject.Leave;
  840.   end;
  841. {$ENDIF}
  842. end; { TProcessorThread.InfoText }
  843. function TProcessorThread.IsDead: Boolean;
  844. begin
  845.   Result :=
  846.     Terminated or
  847.     (FPool.ThreadDeadTimeout > 0) and (FCurState = tcsProcessing) and
  848.     (GetTickCount - uProcessingStart > FPool.ThreadDeadTimeout);
  849.   if Result then
  850.     WriteLog('Thread dead', 5);
  851. end; { TProcessorThread.IsDead }
  852. function TProcessorThread.isFinished: Boolean;
  853. begin
  854.   Result := WaitForSingleObject(Handle, 0) = WAIT_OBJECT_0;
  855. end; { TProcessorThread.isFinished }
  856. function TProcessorThread.isIdle: Boolean;
  857. begin
  858.   // 如果线程状态是 tcsWaiting, tcsCheckingDown
  859.   // 并且 空间时间 > 100ms,
  860.   // 并且 平均等候任务时间大于平均工作时间的 50%
  861.   // 则视为空闲。
  862.   Result :=
  863.     (FCurState in [tcsWaiting, tcsCheckingDown]) and
  864.     (AverageWaitingTime > 100) and
  865.     (AverageWaitingTime * 2 > AverageProcessingTime);
  866. end; { TProcessorThread.isIdle }
  867. function TProcessorThread.NewAverage(OldAvg, NewVal: Integer): Integer;
  868. begin
  869.   Result := (OldAvg * 2 + NewVal) div 3;
  870. end; { TProcessorThread.NewAverage }
  871. procedure TProcessorThread.Terminate;
  872. begin
  873.   WriteLog('TProcessorThread.Terminate', 5);
  874.   inherited Terminate;
  875.   SetEvent(hThreadTerminated);
  876. end; { TProcessorThread.Terminate }
  877. procedure TProcessorThread.WriteLog(const Str: string; Level: Integer = 0);
  878. begin
  879. {$IFNDEF NOLOGS}
  880.   uThreadPool.WriteLog(Str, ThreadID, Level);
  881. {$ENDIF}
  882. end; { TProcessorThread.WriteLog }
  883. {
  884. ******************************* TCriticalSection *******************************
  885. }
  886. constructor TCriticalSection.Create;
  887. begin
  888.   InitializeCriticalSection(FSection);
  889. end; { TCriticalSection.Create }
  890. destructor TCriticalSection.Destroy;
  891. begin
  892.   DeleteCriticalSection(FSection);
  893. end; { TCriticalSection.Destroy }
  894. procedure TCriticalSection.Enter;
  895. begin
  896.   EnterCriticalSection(FSection);
  897. end; { TCriticalSection.Enter }
  898. procedure TCriticalSection.Leave;
  899. begin
  900.   LeaveCriticalSection(FSection);
  901. end; { TCriticalSection.Leave }
  902. function TCriticalSection.TryEnter: Boolean;
  903. begin
  904.   Result := TryEnterCriticalSection(FSection);
  905. end; { TCriticalSection.TryEnter }
  906. procedure NoLogs(const Str: string; LogID: Integer = 0; Level: Integer = 0);
  907. begin
  908. end;
  909. initialization
  910.   WriteLog := NoLogs;
  911. end.

使用方法
  1. // 创建线程池
  2. FThreadPool := TThreadsPool.Create(Self); // 创建线程池
  3. FThreadPool.ThreadsMin := 5; // 初始工作线程数
  4. FThreadPool.ThreadsMax := 50; // 最大允许工作线程数
  5. FThreadPool.OnProcessRequest := DealwithCommRecvData; // 线程工作函数(DealwithCommRecvData在工作者线程的Execute方法中被调用)
  6. // 使用线程池
  7. var
  8.  AWorkItem: TRecvCommDataWorkItem; // 继承自TWorkItem
  9. begin
  10.  AWorkItem := TRecvCommDataWorkItem.Create;
  11.  Move(PData[0], AWorkItem.FRecvData[0], PDataLen);
  12.  AWorkItem.FRecvDataLen := PDataLen;
  13.  FThreadPool.AddRequest(AWorkItem); // 向线程池分配一个任务
  14. end;
  15. [/code]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值