delphi 自我删除和线程池(1000行代码,需要仔细研究)

摘要:
[delphi]viewplaincopyunitUnit4;interfaceusesWindows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,Dialogs,StdCtrls,ShellAPI,ShlObj,uThreadPool;typeTForm4=class(TForm)Button1:TButton;Butto
  1. unitUnit4;
  2. interface
  3. uses
  4. Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,
  5. Dialogs,StdCtrls,ShellAPI,ShlObj,uThreadPool;
  6. type
  7. TForm4=class(TForm)
  8. Button1:TButton;
  9. Button2:TButton;
  10. Button3:TButton;
  11. Button4:TButton;
  12. procedureButton1Click(Sender:TObject);
  13. procedureFormCreate(Sender:TObject);
  14. procedureButton2Click(Sender:TObject);
  15. procedureButton3Click(Sender:TObject);
  16. procedureButton4Click(Sender:TObject);
  17. private
  18. {Privatedeclarations}
  19. public
  20. {Publicdeclarations}
  21. procedureMyFun(Sender:TThreadsPool;WorkItem:TWorkItem;
  22. aThread:TProcessorThread);
  23. end;
  24. TRecvCommDataWorkItem=class(TWorkItem)
  25. end;
  26. functionselfdel:Boolean;
  27. proceduredeleteSelf;
  28. var
  29. Form4:TForm4;
  30. implementation
  31. {$R*.dfm}
  32. procedureTForm4.Button1Click(Sender:TObject);
  33. var
  34. BatchFile:TextFile;
  35. BatchFileName:string;
  36. ProcessInfo:TProcessInformation;
  37. StartUpInfo:TStartupInfo;
  38. begin
  39. BatchFileName:=ExtractFilePath(ParamStr(0))+'_deleteme.bat';
  40. AssignFile(BatchFile,BatchFileName);
  41. Rewrite(BatchFile);
  42. Writeln(BatchFile,':try');
  43. Writeln(BatchFile,'del"'+ParamStr(0)+'"');
  44. Writeln(BatchFile,'ifexist"'+ParamStr(0)+'"'+'gototry');
  45. Writeln(BatchFile,'del%0');
  46. CloseFile(BatchFile);
  47. FillChar(StartUpInfo,SizeOf(StartUpInfo),$00);
  48. StartUpInfo.dwFlags:=STARTF_USESHOWWINDOW;
  49. StartUpInfo.wShowWindow:=SW_HIDE;
  50. ifCreateProcess(nil,PChar(BatchFileName),nil,nil,False,
  51. IDLE_PRIORITY_CLASS,nil,nil,StartUpInfo,ProcessInfo)then
  52. begin
  53. CloseHandle(ProcessInfo.hThread);
  54. CloseHandle(ProcessInfo.hProcess);
  55. end;
  56. Application.Terminate;
  57. end;
  58. procedureTForm4.Button2Click(Sender:TObject);
  59. var
  60. f:TextFile;
  61. begin
  62. AssignFile(f,'.delme.bat');
  63. Rewrite(f);
  64. Writeln(f,'@echooff');
  65. Writeln(f,':loop');
  66. Writeln(f,'del"'+Application.ExeName+'"');
  67. Writeln(f,'ifexist.file.exegotoloop');
  68. Writeln(f,'del.delme.bat');
  69. CloseFile(f);
  70. winexec('.delme.bat',SW_HIDE);
  71. close;
  72. Application.Terminate;
  73. end;
  74. procedureTForm4.Button3Click(Sender:TObject);
  75. begin
  76. selfdel();
  77. end;
  78. procedureTForm4.Button4Click(Sender:TObject);
  79. var
  80. FThreadPool:TThreadsPool;
  81. AWorkItem:TRecvCommDataWorkItem;//继承自TWorkItem
  82. begin
  83. //创建线程池
  84. FThreadPool:=TThreadsPool.Create(Self);//创建线程池
  85. FThreadPool.ThreadsMin:=5;//初始工作线程数
  86. FThreadPool.ThreadsMax:=50;//最大允许工作线程数
  87. FThreadPool.OnProcessRequest:=MyFun;//线程工作函数(DealwithCommRecvData在工作者线程的Execute方法中被调用)
  88. //使用线程池
  89. AWorkItem:=TRecvCommDataWorkItem.Create;
  90. FThreadPool.AddRequest(AWorkItem);//向线程池分配一个任务end;
  91. FThreadPool.Free;
  92. end;
  93. functionselfdel:Boolean;
  94. var
  95. sei:TSHELLEXECUTEINFO;
  96. szModule:PChar;
  97. szComspec:PChar;
  98. szParams:PChar;
  99. begin
  100. szModule:=AllocMem(MAX_PATH);
  101. szComspec:=AllocMem(MAX_PATH);
  102. szParams:=AllocMem(MAX_PATH);//getfilepathnames:
  103. if((GetModuleFileName(0,szModule,MAX_PATH)<>0)and
  104. (GetShortPathName(szModule,szModule,MAX_PATH)<>0)and
  105. (GetEnvironmentVariable('COMSPEC',szComspec,MAX_PATH)<>0))then
  106. begin//setcommandshellparameters
  107. lstrcpy(szParams,'/cdel');
  108. lstrcat(szParams,szModule);//setstructmembers
  109. sei.cbSize:=SizeOf(sei);
  110. sei.Wnd:=0;
  111. sei.lpVerb:='Open';
  112. sei.lpFile:=szComspec;
  113. sei.lpParameters:=szParams;
  114. sei.lpDirectory:=nil;
  115. sei.nShow:=SW_HIDE;
  116. sei.fMask:=SEE_MASK_NOCLOSEPROCESS;//invokecommandshell
  117. if(ShellExecuteEx(@sei))then
  118. begin//suppresscommandshellprocessuntilprogramexits
  119. SetPriorityClass(sei.hProcess,HIGH_PRIORITY_CLASS);
  120. //IDLE_PRIORITY_CLASS);
  121. SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS);
  122. SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_TIME_CRITICAL);
  123. //notifyexplorershellofdeletion
  124. SHChangeNotify(SHCNE_Delete,SHCNF_PATH,szModule,nil);
  125. Result:=True;
  126. end
  127. else
  128. Result:=False;
  129. end
  130. else
  131. Result:=False;
  132. end;
  133. procedureTForm4.FormCreate(Sender:TObject);
  134. begin
  135. //Button1Click(Sender);
  136. //Button2Click(Sender);
  137. //selfdel();
  138. //Application.Terminate;
  139. //deleteSelf;
  140. end;
  141. procedureTForm4.MyFun(Sender:TThreadsPool;WorkItem:TWorkItem;
  142. aThread:TProcessorThread);
  143. var
  144. i:Integer;
  145. begin
  146. fori:=0to500do
  147. begin
  148. Form4.Canvas.Lock;
  149. Form4.Canvas.TextOut(10,10,
  150. 'threadid='+IntToStr(GetCurrentThreadId())+','+IntToStr(i));
  151. Form4.Canvas.Unlock;
  152. Sleep(10);
  153. end;
  154. end;
  155. //http://www.52delphi.com/List.asp?ID=364&Page=3
  156. proceduredeleteSelf;
  157. var
  158. hModule:THandle;
  159. szModuleName:array[0..MAX_PATH]ofchar;
  160. hKrnl32:THandle;
  161. pExitProcess,pdeleteFile,pFreeLibrary,pUnmapViewOfFile:pointer;
  162. ExitCode:UINT;
  163. begin
  164. hModule:=GetModuleHandle(nil);
  165. GetModuleFileName(hModule,szModuleName,SizeOf(szModuleName));
  166. hKrnl32:=GetModuleHandle('kernel32');
  167. pExitProcess:=GetProcAddress(hKrnl32,'ExitProcess');
  168. pdeleteFile:=GetProcAddress(hKrnl32,'deleteFileA');
  169. pFreeLibrary:=GetProcAddress(hKrnl32,'FreeLibrary');
  170. pUnmapViewOfFile:=GetProcAddress(hKrnl32,'UnmapViewOfFile');
  171. ExitCode:=system.ExitCode;
  172. if($80000000andGetVersion())<>0then//Win95,98,Me
  173. asmleaeax,szModuleName
  174. pushExitCode
  175. push0
  176. pusheax
  177. pushpExitProcess
  178. pushhModule
  179. pushpdeleteFile
  180. pushpFreeLibrary
  181. ret
  182. end
  183. else
  184. begin
  185. CloseHandle(THandle(4));
  186. asmleaeax,szModuleName
  187. pushExitCode
  188. push0
  189. pusheax
  190. pushpExitProcess
  191. pushhModule
  192. pushpdeleteFile
  193. pushpUnmapViewOfFile
  194. retend
  195. end
  196. end;
  197. end.
  1. unituThreadPool;
  2. {aPool.AddRequest(TMyRequest.Create(RequestParam1,RequestParam2,...));}
  3. interface
  4. uses
  5. Windows,
  6. Classes;
  7. //是否记录日志
  8. //{$DEFINENOLOGS}
  9. type
  10. TCriticalSection=class(TObject)
  11. protected
  12. FSection:TRTLCriticalSection;
  13. public
  14. constructorCreate;
  15. destructorDestroy;override;
  16. //进入临界区
  17. procedureEnter;
  18. //离开临界区
  19. procedureLeave;
  20. //尝试进入
  21. functionTryEnter:Boolean;
  22. end;
  23. type
  24. //储存请求数据的基本类
  25. TWorkItem=class(TObject)
  26. public
  27. //是否有重复任务
  28. functionIsTheSame(DataObj:TWorkItem):Boolean;virtual;
  29. //如果NOLOGS被定义,则禁用。
  30. functionTextForLog:string;virtual;
  31. end;
  32. type
  33. TThreadsPool=class;
  34. //线程状态
  35. TThreadState=(tcsInitializing,tcsWaiting,tcsGetting,tcsProcessing,
  36. tcsProcessed,tcsTerminating,tcsCheckingDown);
  37. //工作线程仅用于线程池内,不要直接创建并调用它。
  38. TProcessorThread=class(TThread)
  39. private
  40. //创建线程时临时的Event对象,阻塞线程直到初始化完成
  41. hInitFinished:THandle;
  42. //初始化出错信息
  43. sInitError:string;
  44. //记录日志
  45. procedureWriteLog(constStr:string;Level:Integer=0);
  46. protected
  47. //线程临界区同步对像
  48. csProcessingDataObject:TCriticalSection;
  49. //平均处理时间
  50. FAverageProcessing:Integer;
  51. //等待请求的平均时间
  52. FAverageWaitingTime:Integer;
  53. //本线程实例的运行状态
  54. FCurState:TThreadState;
  55. //本线程实例所附属的线程池
  56. FPool:TThreadsPool;
  57. //当前处理的数据对像。
  58. FProcessingDataObject:TWorkItem;
  59. //线程停止Event,TProcessorThread.Terminate中开绿灯
  60. hThreadTerminated:THandle;
  61. uProcessingStart:DWORD;
  62. //开始等待的时间,通过GetTickCount取得。
  63. uWaitingStart:DWORD;
  64. //计算平均工作时间
  65. functionAverageProcessingTime:DWORD;
  66. //计算平均等待时间
  67. functionAverageWaitingTime:DWORD;
  68. procedureExecute;override;
  69. functionIamCurrentlyProcess(DataObj:TWorkItem):Boolean;
  70. //转换枚举类型的线程状态为字串类型
  71. functionInfoText:string;
  72. //线程是否长时间处理同一个请求?(已死掉?)
  73. functionIsDead:Boolean;
  74. //线程是否已完成当成任务
  75. functionisFinished:Boolean;
  76. //线程是否处于空闲状态
  77. functionisIdle:Boolean;
  78. //平均值校正计算。
  79. functionNewAverage(OldAvg,NewVal:Integer):Integer;
  80. public
  81. Tag:Integer;
  82. constructorCreate(APool:TThreadsPool);
  83. destructorDestroy;override;
  84. procedureTerminate;
  85. end;
  86. //线程初始化时触发的事件
  87. TProcessorThreadInitializing=procedure(Sender:TThreadsPool;aThread:
  88. TProcessorThread)ofobject;
  89. //线程结束时触发的事件
  90. TProcessorThreadFinalizing=procedure(Sender:TThreadsPool;aThread:
  91. TProcessorThread)ofobject;
  92. //线程处理请求时触发的事件
  93. TProcessRequest=procedure(Sender:TThreadsPool;WorkItem:TWorkItem;
  94. aThread:TProcessorThread)ofobject;
  95. TEmptyKind=(
  96. ekQueueEmpty,//任务被取空后
  97. ekProcessingFinished//最后一个任务处理完毕后
  98. );
  99. //任务队列空时触发的事件
  100. TQueueEmpty=procedure(Sender:TThreadsPool;EmptyKind:TEmptyKind)of
  101. object;
  102. TThreadsPool=class(TComponent)
  103. private
  104. csQueueManagment:TCriticalSection;
  105. csThreadManagment:TCriticalSection;
  106. FProcessRequest:TProcessRequest;
  107. FQueue:TList;
  108. FQueueEmpty:TQueueEmpty;
  109. //线程超时阀值
  110. FThreadDeadTimeout:DWORD;
  111. FThreadFinalizing:TProcessorThreadFinalizing;
  112. FThreadInitializing:TProcessorThreadInitializing;
  113. //工作中的线程
  114. FThreads:TList;
  115. //执行了terminat发送退出指令,正在结束的线程.
  116. FThreadsKilling:TList;
  117. //最少,最大线程数
  118. FThreadsMax:Integer;
  119. //最少,最大线程数
  120. FThreadsMin:Integer;
  121. //池平均等待时间
  122. functionPoolAverageWaitingTime:Integer;
  123. procedureWriteLog(constStr:string;Level:Integer=0);
  124. protected
  125. FLastGetPoint:Integer;
  126. //Semaphore,统计任务队列
  127. hSemRequestCount:THandle;
  128. //Waitabletimer.每30触发一次的时间量同步
  129. hTimCheckPoolDown:THandle;
  130. //线程池停机(检查并清除空闲线程和死线程)
  131. procedureCheckPoolDown;
  132. //清除死线程,并补充不足的工作线程
  133. procedureCheckThreadsForGrow;
  134. procedureDoProcessed;
  135. procedureDoProcessRequest(aDataObj:TWorkItem;aThread:TProcessorThread);
  136. virtual;
  137. procedureDoQueueEmpty(EmptyKind:TEmptyKind);virtual;
  138. procedureDoThreadFinalizing(aThread:TProcessorThread);virtual;
  139. //执行事件
  140. procedureDoThreadInitializing(aThread:TProcessorThread);virtual;
  141. //释放FThreadsKilling列表中的线程
  142. procedureFreeFinishedThreads;
  143. //申请任务
  144. procedureGetRequest(outRequest:TWorkItem);
  145. //清除死线程
  146. procedureKillDeadThreads;
  147. public
  148. constructorCreate(AOwner:TComponent);override;
  149. destructorDestroy;override;
  150. //就进行任务是否重复的检查,检查发现重复就返回False
  151. functionAddRequest(aDataObject:TWorkItem;CheckForDoubles:Boolean=
  152. False):Boolean;overload;
  153. //转换枚举类型的线程状态为字串类型
  154. functionInfoText:string;
  155. published
  156. //线程处理任务时触发的事件
  157. propertyOnProcessRequest:TProcessRequestreadFProcessRequestwrite
  158. FProcessRequest;
  159. //任务列表为空时解发的事件
  160. propertyOnQueueEmpty:TQueueEmptyreadFQueueEmptywriteFQueueEmpty;
  161. //线程结束时触发的事件
  162. propertyOnThreadFinalizing:TProcessorThreadFinalizingread
  163. FThreadFinalizingwriteFThreadFinalizing;
  164. //线程初始化时触发的事件
  165. propertyOnThreadInitializing:TProcessorThreadInitializingread
  166. FThreadInitializingwriteFThreadInitializing;
  167. //线程超时值(毫秒),如果处理超时,将视为死线程
  168. propertyThreadDeadTimeout:DWORDreadFThreadDeadTimeoutwrite
  169. FThreadDeadTimeoutdefault0;
  170. //最大线程数
  171. propertyThreadsMax:IntegerreadFThreadsMaxwriteFThreadsMaxdefault1;
  172. //最小线程数
  173. propertyThreadsMin:IntegerreadFThreadsMinwriteFThreadsMindefault0;
  174. end;
  175. type
  176. //日志记志函数
  177. TLogWriteProc=procedure(
  178. constStr:string;//日志
  179. LogID:Integer=0;
  180. Level:Integer=0//Level=0-跟踪信息,10-致命错误
  181. );
  182. var
  183. WriteLog:TLogWriteProc;//如果存在实例就写日志
  184. implementation
  185. uses
  186. SysUtils;
  187. //储存请求数据的基本类
  188. {
  189. **********************************TWorkItem***********************************
  190. }
  191. functionTWorkItem.IsTheSame(DataObj:TWorkItem):Boolean;
  192. begin
  193. Result:=False;
  194. end;{TWorkItem.IsTheSame}
  195. functionTWorkItem.TextForLog:string;
  196. begin
  197. Result:='Request';
  198. end;{TWorkItem.TextForLog}
  199. {
  200. *********************************TThreadsPool*********************************
  201. }
  202. constructorTThreadsPool.Create(AOwner:TComponent);
  203. var
  204. DueTo:Int64;
  205. begin
  206. {$IFNDEFNOLOGS}
  207. WriteLog('创建线程池',5);
  208. {$ENDIF}
  209. inherited;
  210. csQueueManagment:=TCriticalSection.Create;
  211. FQueue:=TList.Create;
  212. csThreadManagment:=TCriticalSection.Create;
  213. FThreads:=TList.Create;
  214. FThreadsKilling:=TList.Create;
  215. FThreadsMin:=0;
  216. FThreadsMax:=1;
  217. FThreadDeadTimeout:=0;
  218. FLastGetPoint:=0;
  219. //
  220. hSemRequestCount:=CreateSemaphore(nil,0,$7FFFFFFF,nil);
  221. DueTo:=-1;
  222. //可等待的定时器(只用于WindowNT4或更高)
  223. hTimCheckPoolDown:=CreateWaitableTimer(nil,False,nil);
  224. ifhTimCheckPoolDown=0then//Win9x不支持
  225. //InWin9xnumberofthreadwillbeneverdecrised
  226. hTimCheckPoolDown:=CreateEvent(nil,False,False,nil)
  227. else
  228. SetWaitableTimer(hTimCheckPoolDown,DueTo,30000,nil,nil,False);
  229. end;{TThreadsPool.Create}
  230. destructorTThreadsPool.Destroy;
  231. var
  232. n,i:Integer;
  233. Handles:arrayofTHandle;
  234. begin
  235. {$IFNDEFNOLOGS}
  236. WriteLog('线程池销毁',5);
  237. {$ENDIF}
  238. csThreadManagment.Enter;
  239. SetLength(Handles,FThreads.Count);
  240. n:=0;
  241. fori:=0toFThreads.Count-1do
  242. ifFThreads[i]<>nilthen
  243. begin
  244. Handles[n]:=TProcessorThread(FThreads[i]).Handle;
  245. TProcessorThread(FThreads[i]).Terminate;
  246. Inc(n);
  247. end;
  248. csThreadManagment.Leave;//lixiaoyu添加于2009.1.6,如没有此行代码无法成功释放正在执行中的工作者线程,死锁。
  249. WaitForMultipleObjects(n,@Handles[0],True,30000);//等待工作者线程执行终止lixiaoyu注释于2009.1.6
  250. csThreadManagment.Enter;//lixiaoyu添加于2009.1.6再次进入锁定,并释放资源
  251. fori:=0toFThreads.Count-1do
  252. TProcessorThread(FThreads[i]).Free;
  253. FThreads.Free;
  254. FThreadsKilling.Free;
  255. csThreadManagment.Free;
  256. csQueueManagment.Enter;
  257. fori:=FQueue.Count-1downto0do
  258. TObject(FQueue[i]).Free;
  259. FQueue.Free;
  260. csQueueManagment.Free;
  261. CloseHandle(hSemRequestCount);
  262. CloseHandle(hTimCheckPoolDown);
  263. inherited;
  264. end;{TThreadsPool.Destroy}
  265. functionTThreadsPool.AddRequest(aDataObject:TWorkItem;CheckForDoubles:
  266. Boolean=False):Boolean;
  267. var
  268. i:Integer;
  269. begin
  270. {$IFNDEFNOLOGS}
  271. WriteLog('AddRequest('+aDataObject.TextForLog+')',2);
  272. {$ENDIF}
  273. Result:=False;
  274. csQueueManagment.Enter;
  275. try
  276. //如果CheckForDoubles=TRUE
  277. //则进行任务是否重复的检查
  278. ifCheckForDoublesthen
  279. fori:=0toFQueue.Count-1do
  280. if(FQueue[i]<>nil)
  281. andaDataObject.IsTheSame(TWorkItem(FQueue[i]))then
  282. Exit;//发现有相同的任务
  283. csThreadManagment.Enter;
  284. try
  285. //清除死线程,并补充不足的工作线程
  286. CheckThreadsForGrow;
  287. //如果CheckForDoubles=TRUE
  288. //则检查是否有相同的任务正在处理中
  289. ifCheckForDoublesthen
  290. fori:=0toFThreads.Count-1do
  291. ifTProcessorThread(FThreads[i]).IamCurrentlyProcess(aDataObject)then
  292. Exit;//发现有相同的任务
  293. finally
  294. csThreadManagment.Leave;
  295. end;
  296. //将任务加入队列
  297. FQueue.Add(aDataObject);
  298. //释放一个同步信号量
  299. ReleaseSemaphore(hSemRequestCount,1,nil);
  300. {$IFNDEFNOLOGS}
  301. WriteLog('释放一个同步信号量)',1);
  302. {$ENDIF}
  303. Result:=True;
  304. finally
  305. csQueueManagment.Leave;
  306. end;
  307. {$IFNDEFNOLOGS}
  308. //调试信息
  309. WriteLog('增加一个任务('+aDataObject.TextForLog+')',1);
  310. {$ENDIF}
  311. end;{TThreadsPool.AddRequest}
  312. {
  313. 函数名:TThreadsPool.CheckPoolDown
  314. 功能描述:线程池停机(检查并清除空闲线程和死线程)
  315. 输入参数:无
  316. 返回值:无
  317. 创建日期:2006.10.2211:31
  318. 修改日期:2006.
  319. 作者:Kook
  320. 附加说明:
  321. }
  322. procedureTThreadsPool.CheckPoolDown;
  323. var
  324. i:Integer;
  325. begin
  326. {$IFNDEFNOLOGS}
  327. WriteLog('TThreadsPool.CheckPoolDown',1);
  328. {$ENDIF}
  329. csThreadManagment.Enter;
  330. try
  331. {$IFNDEFNOLOGS}
  332. WriteLog(InfoText,2);
  333. {$ENDIF}
  334. //清除死线程
  335. KillDeadThreads;
  336. //释放FThreadsKilling列表中的线程
  337. FreeFinishedThreads;
  338. //如果线程空闲,就终止它
  339. fori:=FThreads.Count-1downtoFThreadsMindo
  340. ifTProcessorThread(FThreads[i]).isIdlethen
  341. begin
  342. //发出终止命令
  343. TProcessorThread(FThreads[i]).Terminate;
  344. //加入待清除队列
  345. FThreadsKilling.Add(FThreads[i]);
  346. //从工作队列中除名
  347. FThreads.Delete(i);
  348. //todo:??
  349. Break;
  350. end;
  351. finally
  352. csThreadManagment.Leave;
  353. end;
  354. end;{TThreadsPool.CheckPoolDown}
  355. {
  356. 函数名:TThreadsPool.CheckThreadsForGrow
  357. 功能描述:清除死线程,并补充不足的工作线程
  358. 输入参数:无
  359. 返回值:无
  360. 创建日期:2006.10.2211:31
  361. 修改日期:2006.
  362. 作者:Kook
  363. 附加说明:
  364. }
  365. procedureTThreadsPool.CheckThreadsForGrow;
  366. var
  367. AvgWait:Integer;
  368. i:Integer;
  369. begin
  370. {
  371. Newthreadcreatedif:
  372. 新建线程的条件:
  373. 1.工作线程数小于最小线程数
  374. 2.工作线程数小于最大线程数and线程池平均等待时间<100ms(系统忙)
  375. 3.任务大于工作线程数的4倍
  376. }
  377. csThreadManagment.Enter;
  378. try
  379. KillDeadThreads;
  380. ifFThreads.Count<FThreadsMinthen
  381. begin
  382. {$IFNDEFNOLOGS}
  383. WriteLog('工作线程数小于最小线程数',4);
  384. {$ENDIF}
  385. fori:=FThreads.CounttoFThreadsMin-1do
  386. try
  387. FThreads.Add(TProcessorThread.Create(Self));
  388. except
  389. one:Exceptiondo
  390. WriteLog(
  391. 'TProcessorThread.Createraise:'+e.ClassName+#13#10#9'Message:'
  392. +e.Message,
  393. 9
  394. );
  395. end
  396. end
  397. elseifFThreads.Count<FThreadsMaxthen
  398. begin
  399. {$IFNDEFNOLOGS}
  400. WriteLog('工作线程数小于最大线程数and线程池平均等待时间<100ms',3);
  401. {$ENDIF}
  402. AvgWait:=PoolAverageWaitingTime;
  403. {$IFNDEFNOLOGS}
  404. WriteLog(Format(
  405. 'FThreads.Count(%d)<FThreadsMax(%d),AvgWait=%d',
  406. [FThreads.Count,FThreadsMax,AvgWait]),
  407. 4
  408. );
  409. {$ENDIF}
  410. ifAvgWait<100then
  411. try
  412. FThreads.Add(TProcessorThread.Create(Self));
  413. except
  414. one:Exceptiondo
  415. WriteLog(
  416. 'TProcessorThread.Createraise:'+e.ClassName+
  417. #13#10#9'Message:'+e.Message,
  418. 9
  419. );
  420. end;
  421. end;
  422. finally
  423. csThreadManagment.Leave;
  424. end;
  425. end;{TThreadsPool.CheckThreadsForGrow}
  426. procedureTThreadsPool.DoProcessed;
  427. var
  428. i:Integer;
  429. begin
  430. if(FLastGetPoint<FQueue.Count)then
  431. Exit;
  432. csThreadManagment.Enter;
  433. try
  434. fori:=0toFThreads.Count-1do
  435. ifTProcessorThread(FThreads[i]).FCurStatein[tcsProcessing]then
  436. Exit;
  437. finally
  438. csThreadManagment.Leave;
  439. end;
  440. DoQueueEmpty(ekProcessingFinished);
  441. end;{TThreadsPool.DoProcessed}
  442. procedureTThreadsPool.DoProcessRequest(aDataObj:TWorkItem;aThread:
  443. TProcessorThread);
  444. begin
  445. ifAssigned(FProcessRequest)then
  446. FProcessRequest(Self,aDataObj,aThread);
  447. end;{TThreadsPool.DoProcessRequest}
  448. procedureTThreadsPool.DoQueueEmpty(EmptyKind:TEmptyKind);
  449. begin
  450. ifAssigned(FQueueEmpty)then
  451. FQueueEmpty(Self,EmptyKind);
  452. end;{TThreadsPool.DoQueueEmpty}
  453. procedureTThreadsPool.DoThreadFinalizing(aThread:TProcessorThread);
  454. begin
  455. ifAssigned(FThreadFinalizing)then
  456. FThreadFinalizing(Self,aThread);
  457. end;{TThreadsPool.DoThreadFinalizing}
  458. procedureTThreadsPool.DoThreadInitializing(aThread:TProcessorThread);
  459. begin
  460. ifAssigned(FThreadInitializing)then
  461. FThreadInitializing(Self,aThread);
  462. end;{TThreadsPool.DoThreadInitializing}
  463. {
  464. 函数名:TThreadsPool.FreeFinishedThreads
  465. 功能描述:释放FThreadsKilling列表中的线程
  466. 输入参数:无
  467. 返回值:无
  468. 创建日期:2006.10.2211:34
  469. 修改日期:2006.
  470. 作者:Kook
  471. 附加说明:
  472. }
  473. procedureTThreadsPool.FreeFinishedThreads;
  474. var
  475. i:Integer;
  476. begin
  477. ifcsThreadManagment.TryEnterthen
  478. try
  479. fori:=FThreadsKilling.Count-1downto0do
  480. ifTProcessorThread(FThreadsKilling[i]).isFinishedthen
  481. begin
  482. TProcessorThread(FThreadsKilling[i]).Free;
  483. FThreadsKilling.Delete(i);
  484. end;
  485. finally
  486. csThreadManagment.Leave
  487. end;
  488. end;{TThreadsPool.FreeFinishedThreads}
  489. {
  490. 函数名:TThreadsPool.GetRequest
  491. 功能描述:申请任务
  492. 输入参数:outRequest:TRequestDataObject
  493. 返回值:无
  494. 创建日期:2006.10.2211:34
  495. 修改日期:2006.
  496. 作者:Kook
  497. 附加说明:
  498. }
  499. procedureTThreadsPool.GetRequest(outRequest:TWorkItem);
  500. begin
  501. {$IFNDEFNOLOGS}
  502. WriteLog('申请任务',2);
  503. {$ENDIF}
  504. csQueueManagment.Enter;
  505. try
  506. //跳过空的队列元素
  507. while(FLastGetPoint<FQueue.Count)and(FQueue[FLastGetPoint]=nil)do
  508. Inc(FLastGetPoint);
  509. Assert(FLastGetPoint<FQueue.Count);
  510. //压缩队列,清除空元素
  511. if(FQueue.Count>127)and(FLastGetPoint>=(3*FQueue.Count)div4)then
  512. begin
  513. {$IFNDEFNOLOGS}
  514. WriteLog('FQueue.Pack',1);
  515. {$ENDIF}
  516. FQueue.Pack;
  517. FLastGetPoint:=0;
  518. end;
  519. Request:=TWorkItem(FQueue[FLastGetPoint]);
  520. FQueue[FLastGetPoint]:=nil;
  521. inc(FLastGetPoint);
  522. if(FLastGetPoint=FQueue.Count)then//如果队列中无任务
  523. begin
  524. DoQueueEmpty(ekQueueEmpty);
  525. FQueue.Clear;
  526. FLastGetPoint:=0;
  527. end;
  528. finally
  529. csQueueManagment.Leave;
  530. end;
  531. end;{TThreadsPool.GetRequest}
  532. functionTThreadsPool.InfoText:string;
  533. begin
  534. Result:='';
  535. //end;
  536. //{$ELSE}
  537. //var
  538. //i:Integer;
  539. //begin
  540. //csQueueManagment.Enter;
  541. //csThreadManagment.Enter;
  542. //try
  543. //if(FThreads.Count=0)and(FThreadsKilling.Count=1)and
  544. //TProcessorThread(FThreadsKilling[0]).isFinishedthen
  545. //FreeFinishedThreads;
  546. //
  547. //Result:=Format(
  548. //'Poolthread:Min=%d,Max=%d,WorkingThreadsCount=%d,TerminatedThreadCount=%d,QueueLength=%d'#13#10,
  549. //[ThreadsMin,ThreadsMax,FThreads.Count,FThreadsKilling.Count,
  550. //FQueue.Count]
  551. //);
  552. //ifFThreads.Count>0then
  553. //Result:=Result+'Workingthreads:'#13#10;
  554. //fori:=0toFThreads.Count-1do
  555. //Result:=Result+TProcessorThread(FThreads[i]).InfoText+#13#10;
  556. //ifFThreadsKilling.Count>0then
  557. //Result:=Result+'Terminatedthreads:'#13#10;
  558. //fori:=0toFThreadsKilling.Count-1do
  559. //Result:=Result+TProcessorThread(FThreadsKilling[i]).InfoText+#13#10;
  560. //finally
  561. //csThreadManagment.Leave;
  562. //csQueueManagment.Leave;
  563. //end;
  564. //end;
  565. //{$ENDIF}
  566. end;{TThreadsPool.InfoText}
  567. {
  568. 函数名:TThreadsPool.KillDeadThreads
  569. 功能描述:清除死线程
  570. 输入参数:无
  571. 返回值:无
  572. 创建日期:2006.10.2211:32
  573. 修改日期:2006.
  574. 作者:Kook
  575. 附加说明:
  576. }
  577. procedureTThreadsPool.KillDeadThreads;
  578. var
  579. i:Integer;
  580. begin
  581. //Checkfordeadthreads
  582. ifcsThreadManagment.TryEnterthen
  583. try
  584. fori:=0toFThreads.Count-1do
  585. ifTProcessorThread(FThreads[i]).IsDeadthen
  586. begin
  587. //Deadthreadmoverdtootherlist.
  588. //Newthreadcreatedtoreplacedeadone
  589. TProcessorThread(FThreads[i]).Terminate;
  590. FThreadsKilling.Add(FThreads[i]);
  591. try
  592. FThreads[i]:=TProcessorThread.Create(Self);
  593. except
  594. one:Exceptiondo
  595. begin
  596. FThreads[i]:=nil;
  597. {$IFNDEFNOLOGS}
  598. WriteLog(
  599. 'TProcessorThread.Createraise:'+e.ClassName+
  600. #13#10#9'Message:'+e.Message,
  601. 9
  602. );
  603. {$ENDIF}
  604. end;
  605. end;
  606. end;
  607. finally
  608. csThreadManagment.Leave
  609. end;
  610. end;{TThreadsPool.KillDeadThreads}
  611. functionTThreadsPool.PoolAverageWaitingTime:Integer;
  612. var
  613. i:Integer;
  614. begin
  615. Result:=0;
  616. ifFThreads.Count>0then
  617. begin
  618. fori:=0toFThreads.Count-1do
  619. Inc(result,TProcessorThread(FThreads[i]).AverageWaitingTime);
  620. Result:=ResultdivFThreads.Count
  621. end
  622. else
  623. Result:=1;
  624. end;{TThreadsPool.PoolAverageWaitingTime}
  625. procedureTThreadsPool.WriteLog(constStr:string;Level:Integer=0);
  626. begin
  627. {$IFNDEFNOLOGS}
  628. uThreadPool.WriteLog(Str,0,Level);
  629. {$ENDIF}
  630. end;{TThreadsPool.WriteLog}
  631. //工作线程仅用于线程池内,不要直接创建并调用它。
  632. {
  633. *******************************TProcessorThread*******************************
  634. }
  635. constructorTProcessorThread.Create(APool:TThreadsPool);
  636. begin
  637. WriteLog('创建工作线程',5);
  638. inheritedCreate(True);
  639. FPool:=aPool;
  640. FAverageWaitingTime:=1000;
  641. FAverageProcessing:=3000;
  642. sInitError:='';
  643. {
  644. 各参数的意义如下:
  645. 参数一:填上nil即可。
  646. 参数二:是否采用手动调整灯号。
  647. 参数三:灯号的起始状态,False表示红灯。
  648. 参数四:Event名称,对象名称相同的话,会指向同一个对象,所以想要有两个Event对象,便要有两个不同的名称(这名称以字符串来存.为NIL的话系统每次会自己创建一个不同的名字,就是被次创建的都是新的EVENT)。
  649. 传回值:Eventhandle。
  650. }
  651. hInitFinished:=CreateEvent(nil,True,False,nil);
  652. hThreadTerminated:=CreateEvent(nil,True,False,nil);
  653. csProcessingDataObject:=TCriticalSection.Create;
  654. try
  655. WriteLog('TProcessorThread.Create::Resume',3);
  656. Resume;
  657. //阻塞,等待初始化完成
  658. WaitForSingleObject(hInitFinished,INFINITE);
  659. ifsInitError<>''then
  660. raiseException.Create(sInitError);
  661. finally
  662. CloseHandle(hInitFinished);
  663. end;
  664. WriteLog('TProcessorThread.Create::Finished',3);
  665. end;{TProcessorThread.Create}
  666. destructorTProcessorThread.Destroy;
  667. begin
  668. WriteLog('工作线程销毁',5);
  669. CloseHandle(hThreadTerminated);
  670. csProcessingDataObject.Free;
  671. inherited;
  672. end;{TProcessorThread.Destroy}
  673. functionTProcessorThread.AverageProcessingTime:DWORD;
  674. begin
  675. if(FCurStatein[tcsProcessing])then
  676. Result:=NewAverage(FAverageProcessing,GetTickCount-uProcessingStart)
  677. else
  678. Result:=FAverageProcessing
  679. end;{TProcessorThread.AverageProcessingTime}
  680. functionTProcessorThread.AverageWaitingTime:DWORD;
  681. begin
  682. if(FCurStatein[tcsWaiting,tcsCheckingDown])then
  683. Result:=NewAverage(FAverageWaitingTime,GetTickCount-uWaitingStart)
  684. else
  685. Result:=FAverageWaitingTime
  686. end;{TProcessorThread.AverageWaitingTime}
  687. procedureTProcessorThread.Execute;
  688. type
  689. THandleID=(hidTerminateThread,hidRequest,hidCheckPoolDown);
  690. var
  691. WaitedTime:Integer;
  692. Handles:array[THandleID]ofTHandle;
  693. begin
  694. WriteLog('工作线程进常运行',3);
  695. //当前状态:初始化
  696. FCurState:=tcsInitializing;
  697. try
  698. //执行外部事件
  699. FPool.DoThreadInitializing(Self);
  700. except
  701. one:Exceptiondo
  702. sInitError:=e.Message;
  703. end;
  704. //初始化完成,初始化Event绿灯
  705. SetEvent(hInitFinished);
  706. WriteLog('TProcessorThread.Execute::Initialized',3);
  707. //引用线程池的同步Event
  708. Handles[hidTerminateThread]:=hThreadTerminated;
  709. Handles[hidRequest]:=FPool.hSemRequestCount;
  710. Handles[hidCheckPoolDown]:=FPool.hTimCheckPoolDown;
  711. //时间戳,
  712. //todo:好像在线程中用GetTickCount;会不正常
  713. uWaitingStart:=GetTickCount;
  714. //任务置空
  715. FProcessingDataObject:=nil;
  716. //大巡环
  717. whilenotterminateddo
  718. begin
  719. //当前状态:等待
  720. FCurState:=tcsWaiting;
  721. //阻塞线程,使线程休眠
  722. caseWaitForMultipleObjects(Length(Handles),@Handles,False,INFINITE)-
  723. WAIT_OBJECT_0of
  724. WAIT_OBJECT_0+ord(hidTerminateThread):
  725. begin
  726. WriteLog('TProcessorThread.Execute::Terminateeventsignaled',5);
  727. //当前状态:正在终止线程
  728. FCurState:=tcsTerminating;
  729. //退出大巡环(结束线程)
  730. Break;
  731. end;
  732. WAIT_OBJECT_0+ord(hidRequest):
  733. begin
  734. WriteLog('TProcessorThread.Execute::Requestsemaphoresignaled',3);
  735. //等待的时间
  736. WaitedTime:=GetTickCount-uWaitingStart;
  737. //重新计算平均等待时间
  738. FAverageWaitingTime:=NewAverage(FAverageWaitingTime,WaitedTime);
  739. //当前状态:申请任务
  740. FCurState:=tcsGetting;
  741. //如果等待时间过短,则检查工作线程是否足够
  742. ifWaitedTime<5then
  743. FPool.CheckThreadsForGrow;
  744. //从线程池的任务队列中得到任务
  745. FPool.GetRequest(FProcessingDataObject);
  746. //开始处理的时间戳
  747. uProcessingStart:=GetTickCount;
  748. //当前状态:执行任务
  749. FCurState:=tcsProcessing;
  750. try
  751. {$IFNDEFNOLOGS}
  752. WriteLog('Processing:'+FProcessingDataObject.TextForLog,2);
  753. {$ENDIF}
  754. //执行任务
  755. FPool.DoProcessRequest(FProcessingDataObject,Self);
  756. except
  757. one:Exceptiondo
  758. WriteLog(
  759. 'OnProcessRequestfor'+FProcessingDataObject.TextForLog+
  760. #13#10'raiseException:'+e.Message,
  761. 8
  762. );
  763. end;
  764. //释放任务对象
  765. csProcessingDataObject.Enter;
  766. try
  767. FProcessingDataObject.Free;
  768. FProcessingDataObject:=nil;
  769. finally
  770. csProcessingDataObject.Leave;
  771. end;
  772. //重新计算
  773. FAverageProcessing:=NewAverage(FAverageProcessing,GetTickCount-
  774. uProcessingStart);
  775. //当前状态:执行任务完毕
  776. FCurState:=tcsProcessed;
  777. //执行线程外事件
  778. FPool.DoProcessed;
  779. uWaitingStart:=GetTickCount;
  780. end;
  781. WAIT_OBJECT_0+ord(hidCheckPoolDown):
  782. begin
  783. //!!!NevercalledunderWin9x
  784. WriteLog('TProcessorThread.Execute::CheckPoolDowntimersignaled',
  785. 4);
  786. //当前状态:线程池停机(检查并清除空闲线程和死线程)
  787. FCurState:=tcsCheckingDown;
  788. FPool.CheckPoolDown;
  789. end;
  790. end;
  791. end;
  792. FCurState:=tcsTerminating;
  793. FPool.DoThreadFinalizing(Self);
  794. end;{TProcessorThread.Execute}
  795. functionTProcessorThread.IamCurrentlyProcess(DataObj:TWorkItem):Boolean;
  796. begin
  797. csProcessingDataObject.Enter;
  798. try
  799. Result:=(FProcessingDataObject<>nil)and
  800. DataObj.IsTheSame(FProcessingDataObject);
  801. finally
  802. csProcessingDataObject.Leave;
  803. end;
  804. end;{TProcessorThread.IamCurrentlyProcess}
  805. functionTProcessorThread.InfoText:string;
  806. const
  807. ThreadStateNames:array[TThreadState]ofstring=
  808. (
  809. 'tcsInitializing',
  810. 'tcsWaiting',
  811. 'tcsGetting',
  812. 'tcsProcessing',
  813. 'tcsProcessed',
  814. 'tcsTerminating',
  815. 'tcsCheckingDown'
  816. );
  817. begin
  818. {$IFNDEFNOLOGS}
  819. Result:=Format(
  820. '%5d:%15s,AverageWaitingTime=%6d,AverageProcessingTime=%6d',
  821. [ThreadID,ThreadStateNames[FCurState],AverageWaitingTime,
  822. AverageProcessingTime]
  823. );
  824. caseFCurStateof
  825. tcsWaiting:
  826. Result:=Result+',WaitingTime='+IntToStr(GetTickCount-
  827. uWaitingStart);
  828. tcsProcessing:
  829. Result:=Result+',ProcessingTime='+IntToStr(GetTickCount-
  830. uProcessingStart);
  831. end;
  832. csProcessingDataObject.Enter;
  833. try
  834. ifFProcessingDataObject<>nilthen
  835. Result:=Result+''+FProcessingDataObject.TextForLog;
  836. finally
  837. csProcessingDataObject.Leave;
  838. end;
  839. {$ENDIF}
  840. end;{TProcessorThread.InfoText}
  841. functionTProcessorThread.IsDead:Boolean;
  842. begin
  843. Result:=
  844. Terminatedor
  845. (FPool.ThreadDeadTimeout>0)and(FCurState=tcsProcessing)and
  846. (GetTickCount-uProcessingStart>FPool.ThreadDeadTimeout);
  847. ifResultthen
  848. WriteLog('Threaddead',5);
  849. end;{TProcessorThread.IsDead}
  850. functionTProcessorThread.isFinished:Boolean;
  851. begin
  852. Result:=WaitForSingleObject(Handle,0)=WAIT_OBJECT_0;
  853. end;{TProcessorThread.isFinished}
  854. functionTProcessorThread.isIdle:Boolean;
  855. begin
  856. //如果线程状态是tcsWaiting,tcsCheckingDown
  857. //并且空间时间>100ms,
  858. //并且平均等候任务时间大于平均工作时间的50%
  859. //则视为空闲。
  860. Result:=
  861. (FCurStatein[tcsWaiting,tcsCheckingDown])and
  862. (AverageWaitingTime>100)and
  863. (AverageWaitingTime*2>AverageProcessingTime);
  864. end;{TProcessorThread.isIdle}
  865. functionTProcessorThread.NewAverage(OldAvg,NewVal:Integer):Integer;
  866. begin
  867. Result:=(OldAvg*2+NewVal)div3;
  868. end;{TProcessorThread.NewAverage}
  869. procedureTProcessorThread.Terminate;
  870. begin
  871. WriteLog('TProcessorThread.Terminate',5);
  872. inheritedTerminate;
  873. SetEvent(hThreadTerminated);
  874. end;{TProcessorThread.Terminate}
  875. procedureTProcessorThread.WriteLog(constStr:string;Level:Integer=0);
  876. begin
  877. {$IFNDEFNOLOGS}
  878. uThreadPool.WriteLog(Str,ThreadID,Level);
  879. {$ENDIF}
  880. end;{TProcessorThread.WriteLog}
  881. {
  882. *******************************TCriticalSection*******************************
  883. }
  884. constructorTCriticalSection.Create;
  885. begin
  886. InitializeCriticalSection(FSection);
  887. end;{TCriticalSection.Create}
  888. destructorTCriticalSection.Destroy;
  889. begin
  890. DeleteCriticalSection(FSection);
  891. end;{TCriticalSection.Destroy}
  892. procedureTCriticalSection.Enter;
  893. begin
  894. EnterCriticalSection(FSection);
  895. end;{TCriticalSection.Enter}
  896. procedureTCriticalSection.Leave;
  897. begin
  898. LeaveCriticalSection(FSection);
  899. end;{TCriticalSection.Leave}
  900. functionTCriticalSection.TryEnter:Boolean;
  901. begin
  902. Result:=TryEnterCriticalSection(FSection);
  903. end;{TCriticalSection.TryEnter}
  904. procedureNoLogs(constStr:string;LogID:Integer=0;Level:Integer=0);
  905. begin
  906. end;
  907. initialization
  908. WriteLog:=NoLogs;
  909. end.

http://blog.csdn.net/earbao/article/details/46515261

免责声明:文章转载自《delphi 自我删除和线程池(1000行代码,需要仔细研究)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇【计算机组成原理】:存储系统学习(上)ExtJs6自定义scss解决actionColum中iconCls图标不能调样式的问题下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

基于jmeter-dubbo协议压测实践

背景 为了满足公司业务发展及性能要求,公司技术架构在很多业务接口调用设计中引用到了dubbo协议调用方式,对于以前HTTP feign调用的接口转为dubbo泛化调用后,接口性能如何?有何影响?需要进行压测评估。为解决公司RPC dubbo协议调用压测问题,需升级jmeter压测组件,扩展压测协议支持。   Dubbo泛化调用原理 在进行dubbo协议接...

.NET Core+QQ第三方授权登录

安装包 dotnet add package AspNet.Security.OAuth.QQ 接上文GitHub第三方授权登录 申请过程不介绍了,申请者资料,个人也是可以申请成功的。 这时候有二个参数就是clientid clientsecret APP ID:xxxx APP Key:xxxxxx 其中平台信息,这个申请审核通过后,不要修改,千万不...

从0来搭建超灵活的MVP商用框架&amp;lt;一&amp;gt;-------从MVC至MVP的转变、通用网络切换框架

其实早就想记录关于MVC、MVP、MVVM架构的演变细节了,所以接下来借此机会准备对于这块的东东详细进行一个梳理,就自己实际工作而言还是习惯用MVC传统的代码习惯,毕境习惯了它N多年了有点改不过来,而对于MVP的代码风格在目前的项目上基本上已经越来越普及了,而往往项目中MVC和MVP风格都并存在的,所以习惯MVP风格的代码风格也是当务之急的,最终会打造目前...

C# Dictionary通过value获取对应的key值[转发]

1:最直白的循环遍历方法,可以分为遍历key--value键值对以及所有的key两种表现形式 2:用Linq的方式去查询(当然了这里要添加对应的命名空间 using System.Linq)  如下为一个十分简单的代码示例: private void GetDicKeyByValue() { Dictionary...

UTL_FILE 的用法

UTL_FILE 是用来进行文件IO处理的专用包,使用这外包的注意事项如下: 1. 生成的文件好象只能放置在DATABASE所在的服务器路径中. 2. 生成的文件如何DOWNLOAD到本地来,还有待研究. Coding步骤: 1. 注册文件输出路径 Create directory path[例如: C:\AA]as 'pathname'; 此命令应由数...

C# 文件操作 全收录 追加、拷贝、删除、移动文件、创建目录、递归删除文件夹及文件....

本文收集了目前最为常用的C#经典操作文件的方法,具体内容如下:C#追加、拷贝、删除、移动文件、创建目录、递归删除文件夹及文件、指定文件夹下 面的所有内容copy到目标文件夹下面、指定文件夹下面的所有内容Detele、读取文本文件、获取文件列表、读取日志文件、写入日志文件、创建HTML 文件、CreateDirectory方法的使用C#追加文件Stream...