📄 jvqmtthreading.pas
字号:
{******************************************************************************}
{* WARNING: JEDI VCL To CLX Converter generated unit. *}
{* Manual modifications will be lost on next release. *}
{******************************************************************************}
{-----------------------------------------------------------------------------
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/MPL-1.1.html
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
the specific language governing rights and limitations under the License.
The Original Code is: MTThreading.pas, released on 2000-09-22.
The Initial Developer of the Original Code is Erwin Molendijk.
Portions created by Erwin Molendijk are Copyright (C) 2002 Erwin Molendijk.
All Rights Reserved.
Contributor(s): ______________________________________.
You may retrieve the latest version of this file at the Project JEDI home page,
located at http://www.delphi-jedi.org
Known Issues:
-----------------------------------------------------------------------------}
// $Id: JvQMTThreading.pas,v 1.29 2005/02/06 14:06:14 asnepvangers Exp $
unit JvQMTThreading;
{$I jvcl.inc}
interface
uses
SysUtils, Classes, SyncObjs, Contnrs,
{$IFDEF MSWINDOWS}
Windows, Messages,
{$ENDIF MSWINDOWS}
{$IFDEF HAS_UNIT_LIBC}
Libc,
{$ENDIF HAS_UNIT_LIBC}
{$IFDEF UNIX}
QWindows,
{$ENDIF UNIX}
JvQMTConsts, JvQMTSync;
type
TMTManager = class;
TMTThread = class;
TMTEvent = procedure(Thread: TMTThread) of object;
TIntThread = TThread;
TMTInternalThread = class(TIntThread)
private
FName: string;
FOnExecute: TNotifyEvent;
protected
procedure Execute; override;
procedure RaiseName;
public
property Name: string read FName write FName;
property OnExecute: TNotifyEvent read FOnExecute write FOnExecute;
end;
TMTThread = class(TObject)
private
FFinished: Boolean;
FIntThread: TMTInternalThread;
FManager: TMTManager;
FName: string;
FOnExecute: TMTEvent;
FOnFinished: TMTEvent;
FOnTerminating: TMTEvent;
FReferenceCount: Integer;
FStatusChange: TCriticalSection;
FTerminateSignal: THandle;
FTicket: TMTTicket;
procedure CreateAndRun;
function GetStatus: TMTThreadStatus;
procedure Log(const Msg: string);
procedure OnIntThreadExecute(Sender: TObject);
procedure OnIntThreadTerminate(Sender: TObject);
procedure SetName(const Value: string);
protected
procedure DecRef;
procedure IncRef;
public
constructor Create(Manager: TMTManager; Ticket: Integer);
destructor Destroy; override;
procedure CheckTerminate;
procedure Release;
procedure Run;
procedure Synchronize(Method: TThreadMethod);
procedure Terminate;
procedure Wait;
property Name: string read FName write SetName;
property OnExecute: TMTEvent read FOnExecute write FOnExecute;
property OnFinished: TMTEvent read FOnFinished write FOnFinished;
property OnTerminating: TMTEvent read FOnTerminating write FOnTerminating;
property ReferenceCount: Integer read FReferenceCount;
property Status: TMTThreadStatus read GetStatus;
property TerminateSignal: THandle read FTerminateSignal;
property ThreadManager: TMTManager read FManager;
property Ticket: TMTTicket read FTicket;
end;
TMTManager = class(TObject)
private
FGenTicket: TCriticalSection;
FNextTicket: TMTTicket;
FThreads: TObjectList;
FThreadsChange: TCriticalSection;
function FindThread(Ticket: TMTTicket; var Thread: TMTThread): Boolean;
function GenerateTicket: TMTTicket;
procedure Log(const Msg: string);
procedure TryRemoveThread(Thread: TMTThread);
function InternalActiveThreads(RaiseID: Longword): Integer;
protected
procedure OnThreadFinished(Thread: TMTThread);
public
constructor Create;
destructor Destroy; override;
function AcquireNewThread: TMTThread;
function AcquireThread(Ticket: TMTTicket; var Thread: TMTThread): Boolean;
function ActiveThreads: Boolean;
procedure ReleaseThread(Ticket: TMTTicket);
procedure TerminateThreads;
procedure WaitThreads;
end;
function CurrentMTThread: TMTThread;
implementation
uses
{$IFDEF UNITVERSIONING}
JclUnitVersioning,
{$ENDIF UNITVERSIONING}
JvQResources;
threadvar
_CurrentMTThread: TMTThread;
function CurrentMTThread: TMTThread;
begin
Result := _CurrentMTThread;
end;
//=== { TMTInternalThread } ==================================================
procedure TMTInternalThread.Execute;
begin
RaiseName;
if Assigned(FOnExecute) then
FOnExecute(Self);
end;
procedure TMTInternalThread.RaiseName;
var
ThreadNameInfo: TThreadNameInfo;
begin
ThreadNameInfo.FType := $1000;
ThreadNameInfo.FName := PChar(FName);
ThreadNameInfo.FThreadID := $FFFFFFFF;
ThreadNameInfo.FFlags := 0;
try
RaiseException($406D1388, 0, SizeOf(ThreadNameInfo) div SizeOf(Longword),
@ThreadNameInfo);
except
end;
end;
//=== { TMTThread } ==========================================================
constructor TMTThread.Create(Manager: TMTManager; Ticket: Integer);
begin
inherited Create;
FStatusChange := TCriticalSection.Create;
FManager := Manager;
FTicket := Ticket;
FName := 'MT' + IntToStr(Ticket); // do not localize
FTerminateSignal := CreateSemaphore(nil, 0, 1, '');
end;
destructor TMTThread.Destroy;
begin
CloseHandle(FTerminateSignal);
FStatusChange.Free;
inherited Destroy;
end;
procedure TMTThread.CheckTerminate;
begin
if CurrentMTThread <> Self then
raise EMTThreadError.CreateRes(@RsECheckTerminateCalledByWrongThread);
if Status = tsTerminating then
raise EMTTerminateError.Create('');
end;
procedure TMTThread.CreateAndRun;
begin
FStatusChange.Acquire;
try
FIntThread := TMTInternalThread.Create(True);
FIntThread.OnExecute := OnIntThreadExecute;
FIntThread.OnTerminate := OnIntThreadTerminate;
FIntThread.FreeOnTerminate := True;
FIntThread.Name := FName;
FIntThread.Resume;
finally
FStatusChange.Release;
end;
end;
procedure TMTThread.DecRef;
begin
InterlockedDecrement(FReferenceCount);
end;
function TMTThread.GetStatus: TMTThreadStatus;
begin
FStatusChange.Acquire;
try
if FFinished then
Result := tsFinished
else
if FIntThread = nil then
Result := tsInitializing
else
if FIntThread.Suspended then
Result := tsWaiting
else
if FIntThread.Terminated then
Result := tsTerminating
else
Result := tsRunning;
finally
FStatusChange.Release;
end;
end;
procedure TMTThread.IncRef;
begin
InterlockedIncrement(FReferenceCount);
end;
procedure TMTThread.Log(const Msg: string);
begin
// (rom) no OutputDebugString in production code
{$IFDEF DEBUGINFO_ON}
OutputDebugString(PChar('[' + ClassName + '] ' + Msg));
{$ENDIF DEBUGINFO_ON}
end;
procedure TMTThread.OnIntThreadExecute(Sender: TObject);
begin
// set the CurrentMTThread variable.
// this variable is global, but only to this thread.
_CurrentMTThread := Self;
// run OnExecute event
try
if Assigned(FOnExecute) then
FOnExecute(Self);
except
on E: EMTTerminateError do
{nothing};
on E: Exception do
Log('OnExecute Exception: "' + E.Message+'"'); // do not localize
end;
// make sure terminate flag is set
FIntThread.Terminate;
// run OnTerminating event
try
if Assigned(FOnTerminating) then
FOnTerminating(Self);
except
on E: Exception do
Log('OnTerminate Exception: "' + E.Message+'"'); // do not localize
end;
end;
procedure TMTThread.OnIntThreadTerminate(Sender: TObject);
begin
FStatusChange.Acquire;
try
if FFinished then
Exit;
FFinished := True;
finally
FStatusChange.Release;
end;
if Assigned(FOnFinished) then
FOnFinished(Self);
FStatusChange.Acquire;
try
FIntThread := nil;
finally
FStatusChange.Release;
end;
// After a call to OnThreadFinished, this object might be destroyed.
// So don't access any fields after this call.
FManager.OnThreadFinished(Self);
end;
procedure TMTThread.Release;
begin
FManager.ReleaseThread(FTicket);
end;
procedure TMTThread.Run;
begin
FStatusChange.Acquire;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -