doublecmd/src/ufunctionthread.pas
2023-06-05 20:42:11 +03:00

192 lines
4.2 KiB
ObjectPascal

{
Double Commander
-------------------------------------------------------------------------
Executing functions in a thread.
Copyright (C) 2009-2011 Przemysław Nagay (cobines@gmail.com)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
}
unit uFunctionThread;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, syncobjs;
type
TFunctionThreadMethod = procedure(Params: Pointer) of object;
PFunctionThreadItem = ^TFunctionThreadItem;
TFunctionThreadItem = record
Method: TFunctionThreadMethod;
Params: Pointer;
end;
TFunctionThread = class(TThread)
private
FFunctionsToCall: TFPList;
FWaitEvent: PRTLEvent;
FLock: TCriticalSection;
FFinished: Boolean;
protected
procedure Execute; override;
public
constructor Create(CreateSuspended: Boolean); reintroduce;
destructor Destroy; override;
procedure QueueFunction(AFunctionToCall: TFunctionThreadMethod; AParams: Pointer = nil);
procedure Finish;
class procedure Finalize(var AThread: TFunctionThread);
property Finished: Boolean read FFinished;
end;
implementation
uses
LCLProc, uDebug, uExceptions
{$IFDEF MSWINDOWS}
, ActiveX
{$ENDIF}
;
constructor TFunctionThread.Create(CreateSuspended: Boolean);
begin
FWaitEvent := RTLEventCreate;
FFunctionsToCall := TFPList.Create;
FLock := TCriticalSection.Create;
FFinished := False;
FreeOnTerminate := False;
inherited Create(CreateSuspended, DefaultStackSize);
end;
destructor TFunctionThread.Destroy;
var
i: Integer;
begin
RTLeventdestroy(FWaitEvent);
FLock.Acquire;
for i := 0 to FFunctionsToCall.Count - 1 do
Dispose(PFunctionThreadItem(FFunctionsToCall[i]));
FLock.Release;
FreeAndNil(FFunctionsToCall);
FreeAndNil(FLock);
inherited Destroy;
end;
procedure TFunctionThread.QueueFunction(AFunctionToCall: TFunctionThreadMethod; AParams: Pointer);
var
pItem: PFunctionThreadItem;
begin
if (not Terminated) and Assigned(AFunctionToCall) then
begin
New(pItem);
pItem^.Method := AFunctionToCall;
pItem^.Params := AParams;
FLock.Acquire;
try
FFunctionsToCall.Add(pItem);
finally
FLock.Release;
end;
RTLeventSetEvent(FWaitEvent);
end;
end;
procedure TFunctionThread.Finish;
begin
Terminate;
RTLeventSetEvent(FWaitEvent);
end;
procedure TFunctionThread.Execute;
var
pItem: PFunctionThreadItem;
begin
{$IFDEF MSWINDOWS}
CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
{$ENDIF}
try
while (not Terminated) or (FFunctionsToCall.Count > 0) do
begin
RTLeventResetEvent(FWaitEvent);
pItem := nil;
FLock.Acquire;
try
if FFunctionsToCall.Count > 0 then
begin
pItem := PFunctionThreadItem(FFunctionsToCall[0]);
FFunctionsToCall.Delete(0);
end;
finally
FLock.Release;
end;
if Assigned(pItem) then
begin
try
pItem^.Method(pItem^.Params);
Dispose(pItem);
except
on e: Exception do
begin
Dispose(pItem);
HandleException(e, Self);
end;
end;
end
else
begin
RTLeventWaitFor(FWaitEvent);
end;
end;
finally
{$IFDEF MSWINDOWS}
CoUninitialize;
{$ENDIF}
FFinished := True;
end;
end;
class procedure TFunctionThread.Finalize(var AThread: TFunctionThread);
begin
AThread.Finish;
{$IF (fpc_version<2) or ((fpc_version=2) and (fpc_release<5))}
If (MainThreadID=GetCurrentThreadID) then
while not AThread.Finished do
CheckSynchronize(100);
{$ENDIF}
AThread.WaitFor;
AThread.Free;
AThread := nil;
end;
end.