- unit Unit4;
-
- interface
-
- uses
- Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
- Dialogs, StdCtrls, ShellAPI, ShlObj, uThreadPool;
-
- type
- TForm4 = class(TForm)
- Button1: TButton;
- Button2: TButton;
- Button3: TButton;
- Button4: TButton;
- procedure Button1Click(Sender: TObject);
- procedure FormCreate(Sender: TObject);
- procedure Button2Click(Sender: TObject);
- procedure Button3Click(Sender: TObject);
- procedure Button4Click(Sender: TObject);
- private
-
- public
-
- procedure MyFun(Sender: TThreadsPool; WorkItem: TWorkItem;
- aThread: TProcessorThread);
- end;
- TRecvCommDataWorkItem=class(TWorkItem)
-
- end;
-
- function selfdel: Boolean;
- procedure deleteSelf;
-
- var
- Form4: TForm4;
-
- implementation
-
- {$R *.dfm}
-
- procedure TForm4.Button1Click(Sender: TObject);
-
- var
- BatchFile: TextFile;
- BatchFileName: string;
- ProcessInfo: TProcessInformation;
- StartUpInfo: TStartupInfo;
- begin
- BatchFileName := ExtractFilePath(ParamStr(0)) + '_deleteme.bat';
- AssignFile(BatchFile, BatchFileName);
- Rewrite(BatchFile);
- Writeln(BatchFile, ':try');
- Writeln(BatchFile, 'del "' + ParamStr(0) + '"');
- Writeln(BatchFile, 'if exist "' + ParamStr(0) + '"' + ' goto try');
- Writeln(BatchFile, 'del %0');
- CloseFile(BatchFile);
- FillChar(StartUpInfo, SizeOf(StartUpInfo), $00);
- StartUpInfo.dwFlags := STARTF_USESHOWWINDOW;
- StartUpInfo.wShowWindow := SW_HIDE;
- if CreateProcess(nil, PChar(BatchFileName), nil, nil, False,
- IDLE_PRIORITY_CLASS, nil, nil, StartUpInfo, ProcessInfo) then
- begin
- CloseHandle(ProcessInfo.hThread);
- CloseHandle(ProcessInfo.hProcess);
- end;
- Application.Terminate;
- end;
-
- procedure TForm4.Button2Click(Sender: TObject);
- var
- f: TextFile;
- begin
- AssignFile(f, '.\delme.bat');
- Rewrite(f);
- Writeln(f, '@echo off');
- Writeln(f, ':loop');
- Writeln(f, 'del "' + Application.ExeName + '"');
- Writeln(f, 'if exist .\file.exe goto loop');
- Writeln(f, 'del .\delme.bat');
- CloseFile(f);
- winexec('.\delme.bat', SW_HIDE);
- close;
- Application.Terminate;
- end;
-
- procedure TForm4.Button3Click(Sender: TObject);
- begin
- selfdel();
- end;
-
- procedure TForm4.Button4Click(Sender: TObject);
- var
- FThreadPool: TThreadsPool;
- AWorkItem: TRecvCommDataWorkItem;
- begin
-
- FThreadPool := TThreadsPool.Create(Self);
- FThreadPool.ThreadsMin := 5;
- FThreadPool.ThreadsMax := 50;
- FThreadPool.OnProcessRequest := MyFun;
-
-
- AWorkItem := TRecvCommDataWorkItem.Create;
-
- FThreadPool.AddRequest(AWorkItem);
-
- FThreadPool.Free;
- end;
-
- function selfdel: Boolean;
- var
- sei: TSHELLEXECUTEINFO;
- szModule: PChar;
- szComspec: PChar;
- szParams: PChar;
- begin
- szModule := AllocMem(MAX_PATH);
- szComspec := AllocMem(MAX_PATH);
- szParams := AllocMem(MAX_PATH);
- if ((GetModuleFileName(0, szModule, MAX_PATH) <> 0) and
- (GetShortPathName(szModule, szModule, MAX_PATH) <> 0) and
- (GetEnvironmentVariable('COMSPEC', szComspec, MAX_PATH) <> 0)) then
- begin
- lstrcpy(szParams, '/c del ');
- lstrcat(szParams, szModule);
- sei.cbSize := SizeOf(sei);
- sei.Wnd := 0;
- sei.lpVerb := 'Open';
- sei.lpFile := szComspec;
- sei.lpParameters := szParams;
- sei.lpDirectory := nil;
- sei.nShow := SW_HIDE;
- sei.fMask := SEE_MASK_NOCLOSEPROCESS;
- if (ShellExecuteEx(@sei)) then
- begin
- SetPriorityClass(sei.hProcess, HIGH_PRIORITY_CLASS);
-
- SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
- SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
-
- SHChangeNotify(SHCNE_Delete, SHCNF_PATH, szModule, nil);
- Result := True;
- end
- else
- Result := False;
- end
- else
- Result := False;
- end;
-
- procedure TForm4.FormCreate(Sender: TObject);
- begin
-
-
-
-
-
- end;
-
- procedure TForm4.MyFun(Sender: TThreadsPool; WorkItem: TWorkItem;
- aThread: TProcessorThread);
- var
- i: Integer;
- begin
- for i := 0 to 500 do
- begin
- Form4.Canvas.Lock;
- Form4.Canvas.TextOut(10, 10,
- 'threadid=' + IntToStr(GetCurrentThreadId()) + ',' + IntToStr(i));
- Form4.Canvas.Unlock;
- Sleep(10);
- end;
- end;
-
- procedure deleteSelf;
- var
- hModule: THandle;
- szModuleName: array [0 .. MAX_PATH] of char;
- hKrnl32: THandle;
- pExitProcess, pdeleteFile, pFreeLibrary, pUnmapViewOfFile: pointer;
- ExitCode: UINT;
- begin
- hModule := GetModuleHandle(nil);
- GetModuleFileName(hModule, szModuleName, SizeOf(szModuleName));
- hKrnl32 := GetModuleHandle('kernel32');
- pExitProcess := GetProcAddress(hKrnl32, 'ExitProcess');
- pdeleteFile := GetProcAddress(hKrnl32, 'deleteFileA');
- pFreeLibrary := GetProcAddress(hKrnl32, 'FreeLibrary');
- pUnmapViewOfFile := GetProcAddress(hKrnl32, 'UnmapViewOfFile');
- ExitCode := system.ExitCode;
- if ($80000000 and GetVersion()) <> 0 then
- asm lea eax, szModuleName
- push ExitCode
- push 0
- push eax
- push pExitProcess
- push hModule
- push pdeleteFile
- push pFreeLibrary
- ret
- end
- else
- begin
- CloseHandle(THandle(4));
- asm lea eax, szModuleName
- push ExitCode
- push 0
- push eax
- push pExitProcess
- push hModule
- push pdeleteFile
- push pUnmapViewOfFile
- ret end
- end
- end;
-
- end.
- unit uThreadPool;
-
-
- interface
- uses
- Windows,
- Classes;
-
-
- type
- TCriticalSection = class(TObject)
- protected
- FSection: TRTLCriticalSection;
- public
- constructor Create;
- destructor Destroy; override;
-
- procedure Enter;
-
- procedure Leave;
-
- function TryEnter: Boolean;
- end;
-
- type
-
- TWorkItem = class(TObject)
- public
-
- function IsTheSame(DataObj: TWorkItem): Boolean; virtual;
-
- function TextForLog: string; virtual;
- end;
-
- type
- TThreadsPool = class;
-
-
- TThreadState = (tcsInitializing, tcsWaiting, tcsGetting, tcsProcessing,
- tcsProcessed, tcsTerminating, tcsCheckingDown);
-
- TProcessorThread = class(TThread)
- private
-
- hInitFinished: THandle;
-
- sInitError: string;
-
- procedure WriteLog(const Str: string; Level: Integer = 0);
- protected
-
- csProcessingDataObject: TCriticalSection;
-
- FAverageProcessing: Integer;
-
- FAverageWaitingTime: Integer;
-
- FCurState: TThreadState;
-
- FPool: TThreadsPool;
-
- FProcessingDataObject: TWorkItem;
-
- hThreadTerminated: THandle;
- uProcessingStart: DWORD;
-
- uWaitingStart: DWORD;
-
- function AverageProcessingTime: DWORD;
-
- function AverageWaitingTime: DWORD;
- procedure Execute; override;
- function IamCurrentlyProcess(DataObj: TWorkItem): Boolean;
-
- function InfoText: string;
-
- function IsDead: Boolean;
-
- function isFinished: Boolean;
-
- function isIdle: Boolean;
-
- function NewAverage(OldAvg, NewVal: Integer): Integer;
- public
- Tag: Integer;
- constructor Create(APool: TThreadsPool);
- destructor Destroy; override;
- procedure Terminate;
- end;
-
-
- TProcessorThreadInitializing = procedure(Sender: TThreadsPool; aThread:
- TProcessorThread) of object;
-
- TProcessorThreadFinalizing = procedure(Sender: TThreadsPool; aThread:
- TProcessorThread) of object;
-
- TProcessRequest = procedure(Sender: TThreadsPool; WorkItem: TWorkItem;
- aThread: TProcessorThread) of object;
- TEmptyKind = (
- ekQueueEmpty,
- ekProcessingFinished
- );
-
- TQueueEmpty = procedure(Sender: TThreadsPool; EmptyKind: TEmptyKind) of
- object;
-
- TThreadsPool = class(TComponent)
- private
- csQueueManagment: TCriticalSection;
- csThreadManagment: TCriticalSection;
- FProcessRequest: TProcessRequest;
- FQueue: TList;
- FQueueEmpty: TQueueEmpty;
-
- FThreadDeadTimeout: DWORD;
- FThreadFinalizing: TProcessorThreadFinalizing;
- FThreadInitializing: TProcessorThreadInitializing;
-
- FThreads: TList;
-
- FThreadsKilling: TList;
-
- FThreadsMax: Integer;
-
- FThreadsMin: Integer;
-
- function PoolAverageWaitingTime: Integer;
- procedure WriteLog(const Str: string; Level: Integer = 0);
- protected
- FLastGetPoint: Integer;
-
- hSemRequestCount: THandle;
-
- hTimCheckPoolDown: THandle;
-
- procedure CheckPoolDown;
-
- procedure CheckThreadsForGrow;
- procedure DoProcessed;
- procedure DoProcessRequest(aDataObj: TWorkItem; aThread: TProcessorThread);
- virtual;
- procedure DoQueueEmpty(EmptyKind: TEmptyKind); virtual;
- procedure DoThreadFinalizing(aThread: TProcessorThread); virtual;
-
- procedure DoThreadInitializing(aThread: TProcessorThread); virtual;
-
- procedure FreeFinishedThreads;
-
- procedure GetRequest(out Request: TWorkItem);
-
- procedure KillDeadThreads;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
-
- function AddRequest(aDataObject: TWorkItem; CheckForDoubles: Boolean =
- False): Boolean; overload;
-
- function InfoText: string;
- published
-
- property OnProcessRequest: TProcessRequest read FProcessRequest write
- FProcessRequest;
-
- property OnQueueEmpty: TQueueEmpty read FQueueEmpty write FQueueEmpty;
-
- property OnThreadFinalizing: TProcessorThreadFinalizing read
- FThreadFinalizing write FThreadFinalizing;
-
- property OnThreadInitializing: TProcessorThreadInitializing read
- FThreadInitializing write FThreadInitializing;
-
- property ThreadDeadTimeout: DWORD read FThreadDeadTimeout write
- FThreadDeadTimeout default 0;
-
- property ThreadsMax: Integer read FThreadsMax write FThreadsMax default 1;
-
- property ThreadsMin: Integer read FThreadsMin write FThreadsMin default 0;
- end;
-
- type
-
- TLogWriteProc = procedure(
- const Str: string;
- LogID: Integer = 0;
- Level: Integer = 0
- );
-
- var
- WriteLog: TLogWriteProc;
-
- implementation
- uses
- SysUtils;
-
-
- function TWorkItem.IsTheSame(DataObj: TWorkItem): Boolean;
- begin
- Result := False;
- end;
-
- function TWorkItem.TextForLog: string;
- begin
- Result := 'Request';
- end;
-
-
- constructor TThreadsPool.Create(AOwner: TComponent);
- var
- DueTo: Int64;
- begin
- {$IFNDEF NOLOGS}
- WriteLog('创建线程池', 5);
- {$ENDIF}
- inherited;
- csQueueManagment := TCriticalSection.Create;
- FQueue := TList.Create;
- csThreadManagment := TCriticalSection.Create;
- FThreads := TList.Create;
- FThreadsKilling := TList.Create;
- FThreadsMin := 0;
- FThreadsMax := 1;
- FThreadDeadTimeout := 0;
- FLastGetPoint := 0;
-
- hSemRequestCount := CreateSemaphore(nil, 0, $7FFFFFFF, nil);
-
- DueTo := -1;
-
- hTimCheckPoolDown := CreateWaitableTimer(nil, False, nil);
-
- if hTimCheckPoolDown = 0 then
-
- hTimCheckPoolDown := CreateEvent(nil, False, False, nil)
- else
- SetWaitableTimer(hTimCheckPoolDown, DueTo, 30000, nil, nil, False);
- end;
-
- destructor TThreadsPool.Destroy;
- var
- n, i: Integer;
- Handles: array of THandle;
- begin
- {$IFNDEF NOLOGS}
- WriteLog('线程池销毁', 5);
- {$ENDIF}
- csThreadManagment.Enter;
-
- SetLength(Handles, FThreads.Count);
- n := 0;
- for i := 0 to FThreads.Count - 1 do
- if FThreads[i] <> nil then
- begin
- Handles[n] := TProcessorThread(FThreads[i]).Handle;
- TProcessorThread(FThreads[i]).Terminate;
- Inc(n);
- end;
-
- csThreadManagment.Leave;
-
- WaitForMultipleObjects(n, @Handles[0], True, 30000);
-
- csThreadManagment.Enter;
- for i := 0 to FThreads.Count - 1 do
- TProcessorThread(FThreads[i]).Free;
- FThreads.Free;
- FThreadsKilling.Free;
- csThreadManagment.Free;
-
- csQueueManagment.Enter;
- for i := FQueue.Count - 1 downto 0 do
- TObject(FQueue[i]).Free;
- FQueue.Free;
- csQueueManagment.Free;
-
- CloseHandle(hSemRequestCount);
- CloseHandle(hTimCheckPoolDown);
- inherited;
- end;
-
- function TThreadsPool.AddRequest(aDataObject: TWorkItem; CheckForDoubles:
- Boolean = False): Boolean;
- var
- i: Integer;
- begin
- {$IFNDEF NOLOGS}
- WriteLog('AddRequest(' + aDataObject.TextForLog + ')', 2);
- {$ENDIF}
- Result := False;
- csQueueManagment.Enter;
- try
-
-
- if CheckForDoubles then
- for i := 0 to FQueue.Count - 1 do
- if (FQueue[i] <> nil)
- and aDataObject.IsTheSame(TWorkItem(FQueue[i])) then
- Exit;
-
- csThreadManagment.Enter;
- try
-
- CheckThreadsForGrow;
-
-
-
- if CheckForDoubles then
- for i := 0 to FThreads.Count - 1 do
- if TProcessorThread(FThreads[i]).IamCurrentlyProcess(aDataObject) then
- Exit;
-
- finally
- csThreadManagment.Leave;
- end;
-
-
- FQueue.Add(aDataObject);
-
-
- ReleaseSemaphore(hSemRequestCount, 1, nil);
- {$IFNDEF NOLOGS}
- WriteLog('释放一个同步信号量)', 1);
- {$ENDIF}
- Result := True;
- finally
- csQueueManagment.Leave;
- end;
- {$IFNDEF NOLOGS}
-
- WriteLog('增加一个任务(' + aDataObject.TextForLog + ')', 1);
- {$ENDIF}
- end;
-
-
- procedure TThreadsPool.CheckPoolDown;
- var
- i: Integer;
- begin
- {$IFNDEF NOLOGS}
- WriteLog('TThreadsPool.CheckPoolDown', 1);
- {$ENDIF}
- csThreadManagment.Enter;
- try
- {$IFNDEF NOLOGS}
- WriteLog(InfoText, 2);
- {$ENDIF}
-
- KillDeadThreads;
-
- FreeFinishedThreads;
-
-
- for i := FThreads.Count - 1 downto FThreadsMin do
- if TProcessorThread(FThreads[i]).isIdle then
- begin
-
- TProcessorThread(FThreads[i]).Terminate;
-
- FThreadsKilling.Add(FThreads[i]);
-
- FThreads.Delete(i);
-
- Break;
- end;
- finally
- csThreadManagment.Leave;
- end;
- end;
-
-
- procedure TThreadsPool.CheckThreadsForGrow;
- var
- AvgWait: Integer;
- i: Integer;
- begin
-
-
- csThreadManagment.Enter;
- try
- KillDeadThreads;
- if FThreads.Count < FThreadsMin then
- begin
- {$IFNDEF NOLOGS}
- WriteLog('工作线程数小于最小线程数', 4);
- {$ENDIF}
- for i := FThreads.Count to FThreadsMin - 1 do
- try
- FThreads.Add(TProcessorThread.Create(Self));
- except
- on e: Exception do
-
- WriteLog(
- 'TProcessorThread.Create raise: ' + e.ClassName + #13#10#9'Message: '
- + e.Message,
- 9
- );
- end
- end
- else if FThreads.Count < FThreadsMax then
- begin
- {$IFNDEF NOLOGS}
- WriteLog('工作线程数小于最大线程数 and 线程池平均等待时间 < 100ms', 3);
- {$ENDIF}
- AvgWait := PoolAverageWaitingTime;
- {$IFNDEF NOLOGS}
- WriteLog(Format(
- 'FThreads.Count (%d)<FThreadsMax(%d), AvgWait=%d',
- [FThreads.Count, FThreadsMax, AvgWait]),
- 4
- );
- {$ENDIF}
-
- if AvgWait < 100 then
- try
- FThreads.Add(TProcessorThread.Create(Self));
- except
- on e: Exception do
- WriteLog(
- 'TProcessorThread.Create raise: ' + e.ClassName +
- #13#10#9'Message: ' + e.Message,
- 9
- );
- end;
- end;
- finally
- csThreadManagment.Leave;
- end;
- end;
-
- procedure TThreadsPool.DoProcessed;
- var
- i: Integer;
- begin
- if (FLastGetPoint < FQueue.Count) then
- Exit;
- csThreadManagment.Enter;
- try
- for i := 0 to FThreads.Count - 1 do
- if TProcessorThread(FThreads[i]).FCurState in [tcsProcessing] then
- Exit;
- finally
- csThreadManagment.Leave;
- end;
- DoQueueEmpty(ekProcessingFinished);
- end;
-
- procedure TThreadsPool.DoProcessRequest(aDataObj: TWorkItem; aThread:
- TProcessorThread);
- begin
- if Assigned(FProcessRequest) then
- FProcessRequest(Self, aDataObj, aThread);
- end;
-
- procedure TThreadsPool.DoQueueEmpty(EmptyKind: TEmptyKind);
- begin
- if Assigned(FQueueEmpty) then
- FQueueEmpty(Self, EmptyKind);
- end;
-
- procedure TThreadsPool.DoThreadFinalizing(aThread: TProcessorThread);
- begin
- if Assigned(FThreadFinalizing) then
- FThreadFinalizing(Self, aThread);
- end;
-
- procedure TThreadsPool.DoThreadInitializing(aThread: TProcessorThread);
- begin
- if Assigned(FThreadInitializing) then
- FThreadInitializing(Self, aThread);
- end;
-
-
- procedure TThreadsPool.FreeFinishedThreads;
- var
- i: Integer;
- begin
- if csThreadManagment.TryEnter then
- try
- for i := FThreadsKilling.Count - 1 downto 0 do
- if TProcessorThread(FThreadsKilling[i]).isFinished then
- begin
- TProcessorThread(FThreadsKilling[i]).Free;
- FThreadsKilling.Delete(i);
- end;
- finally
- csThreadManagment.Leave
- end;
- end;
-
-
- procedure TThreadsPool.GetRequest(out Request: TWorkItem);
- begin
- {$IFNDEF NOLOGS}
- WriteLog('申请任务', 2);
- {$ENDIF}
- csQueueManagment.Enter;
- try
-
- while (FLastGetPoint < FQueue.Count) and (FQueue[FLastGetPoint] = nil) do
- Inc(FLastGetPoint);
-
- Assert(FLastGetPoint < FQueue.Count);
-
- if (FQueue.Count > 127) and (FLastGetPoint >= (3 * FQueue.Count) div 4) then
- begin
- {$IFNDEF NOLOGS}
- WriteLog('FQueue.Pack', 1);
- {$ENDIF}
- FQueue.Pack;
- FLastGetPoint := 0;
- end;
|
请发表评论