838 lines
21 KiB
ObjectPascal
838 lines
21 KiB
ObjectPascal
{-----------------------------------------------------------------------------
|
|
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: MTComponents.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: JvMTComponents.pas 10612 2006-05-19 19:04:09Z jfudickar $
|
|
|
|
unit JvMTComponents;
|
|
|
|
{$I jvcl.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
{$IFDEF USEJVCL}
|
|
{$IFDEF UNITVERSIONING}
|
|
JclUnitVersioning,
|
|
{$ENDIF UNITVERSIONING}
|
|
{$ENDIF USEJVCL}
|
|
SysUtils, Classes, SyncObjs,
|
|
Consts,
|
|
{$IFDEF USEJVCL}
|
|
JvComponentBase,
|
|
{$ENDIF USEJVCL}
|
|
JvMTThreading, JvMTConsts, JvMTData, JvMTSync, JvMTSyncMon;
|
|
|
|
type
|
|
{$IFDEF USEJVCL}
|
|
TJvMTComponent = class(TJvComponent);
|
|
{$ELSE}
|
|
TJvMTComponent = class(TComponent);
|
|
{$ENDIF USEJVCL}
|
|
TJvMTSingleThread = class(TMTThread);
|
|
TJvMTThread = class;
|
|
|
|
TJvMTThreadEvent = procedure (Sender: TJvMTThread;
|
|
MTThread: TJvMTSingleThread) of object;
|
|
|
|
TJvMTManager = class(TJvMTComponent)
|
|
private
|
|
FManager: TMTManager;
|
|
protected
|
|
procedure Notification(AComponent: TComponent; Operation: TOperation);
|
|
override;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
function AcquireNewThread: TJvMTSingleThread;
|
|
function AcquireThread(Ticket: TMTTicket;
|
|
var Thread: TJvMTSingleThread): Boolean;
|
|
function ActiveThreads: Boolean;
|
|
procedure ReleaseThread(Ticket: TMTTicket);
|
|
procedure TerminateThreads;
|
|
procedure WaitThreads;
|
|
end;
|
|
|
|
TJvMTManagedComponent = class(TJvMTComponent)
|
|
private
|
|
FManager: TJvMTManager;
|
|
protected
|
|
procedure Notification(AComponent: TComponent; Operation: TOperation);
|
|
override;
|
|
procedure SetManager(Value: TJvMTManager); virtual;
|
|
published
|
|
property Manager: TJvMTManager read FManager write SetManager;
|
|
end;
|
|
|
|
TJvMTThread = class(TJvMTManagedComponent)
|
|
private
|
|
FOnExecute: TJvMTThreadEvent;
|
|
FOnFinished: TJvMTThreadEvent;
|
|
FOnTerminating: TJvMTThreadEvent;
|
|
FThread: TJvMTSingleThread;
|
|
FRunOnCreate: Boolean;
|
|
function GetStatus: TMTThreadStatus;
|
|
function GetTicket: TMTTicket;
|
|
procedure HookThread;
|
|
procedure OnIntExecute(Thread: TMTThread);
|
|
procedure OnIntFinished(Thread: TMTThread);
|
|
procedure OnIntTerminating(Thread: TMTThread);
|
|
procedure ReleaseThread;
|
|
procedure SetOnExecute(Value: TJvMTThreadEvent);
|
|
procedure SetOnFinished(Value: TJvMTThreadEvent);
|
|
procedure SetOnTerminating(Value: TJvMTThreadEvent);
|
|
procedure UnHookThread;
|
|
protected
|
|
procedure Loaded; override;
|
|
procedure Notification(AComponent: TComponent; Operation: TOperation);
|
|
override;
|
|
procedure SetManager(Value: TJvMTManager); override;
|
|
procedure DoExecute(MTThread: TJvMTSingleThread); dynamic;
|
|
procedure DoFinished(MTThread: TJvMTSingleThread); dynamic;
|
|
procedure DoTerminating(MTThread: TJvMTSingleThread); dynamic;
|
|
public
|
|
destructor Destroy; override;
|
|
procedure CheckTerminate;
|
|
procedure Run;
|
|
procedure RunCopy;
|
|
procedure Synchronize(Method: TThreadMethod);
|
|
procedure Terminate;
|
|
procedure Wait;
|
|
property Status: TMTThreadStatus read GetStatus;
|
|
property Ticket: TMTTicket read GetTicket;
|
|
published
|
|
property RunOnCreate: Boolean read FRunOnCreate write FRunOnCreate;
|
|
property OnExecute: TJvMTThreadEvent read FOnExecute write SetOnExecute;
|
|
property OnFinished: TJvMTThreadEvent read FOnFinished write SetOnFinished;
|
|
property OnTerminating: TJvMTThreadEvent read FOnTerminating write
|
|
SetOnTerminating;
|
|
end;
|
|
|
|
TJvMTSectionBase = class(TJvMTComponent)
|
|
private
|
|
FSync: TSynchroObject;
|
|
function GetActive: Boolean;
|
|
procedure HookSync;
|
|
protected
|
|
procedure CheckInactiveProperty;
|
|
procedure CreateSync; virtual; abstract;
|
|
public
|
|
destructor Destroy; override;
|
|
procedure Enter;
|
|
procedure Leave;
|
|
published
|
|
property Active: Boolean read GetActive;
|
|
end;
|
|
|
|
TJvMTSection = class(TJvMTSectionBase)
|
|
private
|
|
FAllowRecursion: Boolean;
|
|
FInitEntered: Boolean;
|
|
procedure SetAllowRecursion(Value: Boolean);
|
|
procedure SetInitEntered(Value: Boolean);
|
|
protected
|
|
procedure CreateSync; override;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
published
|
|
property AllowRecursion: Boolean read FAllowRecursion write
|
|
SetAllowRecursion default True;
|
|
property InitEntered: Boolean read FInitEntered write SetInitEntered
|
|
default False;
|
|
end;
|
|
|
|
TJvMTCountingSection = class(TJvMTSectionBase)
|
|
private
|
|
FInitCount: Integer;
|
|
FMaxCount: Integer;
|
|
procedure SetInitAndMax(Init,Max: Integer);
|
|
procedure SetInitCount(Value: Integer);
|
|
procedure SetMaxCount(Value: Integer);
|
|
protected
|
|
procedure CreateSync; override;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
published
|
|
property InitCount: Integer read FInitCount write SetInitCount default 0;
|
|
property MaxCount: Integer read FMaxCount write SetMaxCount default 1;
|
|
end;
|
|
|
|
TJvMTAsyncBufferBase = class(TJvMTComponent)
|
|
private
|
|
FBuffer: TMTAsyncBuffer;
|
|
FHooking: TCriticalSection;
|
|
FMaxBufferSize: Integer;
|
|
procedure SetMaxBufferSize(Value: Integer);
|
|
protected
|
|
procedure CreateBuffer; virtual; abstract;
|
|
procedure HookBuffer;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
function Read: TObject;
|
|
procedure Write(AObject: TObject);
|
|
published
|
|
property MaxBufferSize: Integer read FMaxBufferSize write SetMaxBufferSize
|
|
default MTDefaultBufferSize;
|
|
end;
|
|
|
|
TJvMTThreadToVCL = class(TJvMTAsyncBufferBase)
|
|
private
|
|
FOnCanRead: TNotifyEvent;
|
|
protected
|
|
procedure DoCanRead(Sender: TObject); dynamic;
|
|
procedure CreateBuffer; override;
|
|
published
|
|
property OnCanRead: TNotifyEvent read FOnCanRead write FOnCanRead;
|
|
end;
|
|
|
|
TJvMTVCLToThread = class(TJvMTAsyncBufferBase)
|
|
private
|
|
FOnCanWrite: TNotifyEvent;
|
|
protected
|
|
procedure DoCanWrite(Sender: TObject); dynamic;
|
|
procedure CreateBuffer; override;
|
|
procedure Loaded; override;
|
|
published
|
|
property OnCanWrite: TNotifyEvent read FOnCanWrite write FOnCanWrite;
|
|
end;
|
|
|
|
TJvMTThreadToThread = class(TJvMTComponent)
|
|
private
|
|
FHooking: TCriticalSection;
|
|
FMaxBufferSize: Integer;
|
|
FQueue: TMTBoundedQueue;
|
|
procedure HookQueue;
|
|
procedure SetMaxBufferSize(Value: Integer);
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
function Read: TObject;
|
|
procedure Write(AObject: TObject);
|
|
published
|
|
property MaxBufferSize: Integer read FMaxBufferSize write SetMaxBufferSize
|
|
default MTDefaultBufferSize;
|
|
end;
|
|
|
|
TJvMTMonitorSection = class(TJvMTComponent)
|
|
private
|
|
FMonitor: TMTMonitor;
|
|
function GetCondition(ID: Integer): TMTCondition;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure Enter;
|
|
procedure Leave;
|
|
property Condition[ID: Integer]: TMTCondition read GetCondition; default;
|
|
end;
|
|
|
|
{$IFDEF USEJVCL}
|
|
{$IFDEF UNITVERSIONING}
|
|
const
|
|
UnitVersioning: TUnitVersionInfo = (
|
|
RCSfile: '$URL: https://jvcl.svn.sourceforge.net/svnroot/jvcl/tags/JVCL3_32/run/JvMTComponents.pas $';
|
|
Revision: '$Revision: 10612 $';
|
|
Date: '$Date: 2006-05-19 21:04:09 +0200 (ven., 19 mai 2006) $';
|
|
LogPath: 'JVCL\run'
|
|
);
|
|
{$ENDIF UNITVERSIONING}
|
|
{$ENDIF USEJVCL}
|
|
|
|
implementation
|
|
|
|
{$IFDEF USEJVCL}
|
|
uses
|
|
JvResources;
|
|
{$ENDIF USEJVCL}
|
|
|
|
{$IFNDEF USEJVCL}
|
|
resourcestring
|
|
RsENoThreadManager = 'No ThreadManager specified';
|
|
RsEOperatorNotAvailable = 'Operation not available while thread is active';
|
|
RsECannotChangePropertySection = 'Cannot change property of active section';
|
|
RsECannotChangePropertyBuffer = 'Cannot change property of active buffer';
|
|
{$ENDIF !USEJVCL}
|
|
|
|
constructor TJvMTManager.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
|
|
// We want to know about the form going down
|
|
if AOwner <> nil then
|
|
AOwner.FreeNotification(Self);
|
|
|
|
// hook to a manager object if not designing in the IDE
|
|
if not (csDesigning in ComponentState) then
|
|
FManager := TMTManager.Create;
|
|
end;
|
|
|
|
destructor TJvMTManager.Destroy;
|
|
begin
|
|
// call inherited destroy, this will send Notification's to all the mtcThread
|
|
// components. These will release all their threads.
|
|
inherited Destroy;
|
|
|
|
// Now all threads have been released.
|
|
// Free the manager and the threads belonging to this manager.
|
|
FManager.Free;
|
|
end;
|
|
|
|
function TJvMTManager.AcquireNewThread: TJvMTSingleThread;
|
|
begin
|
|
Result := TJvMTSingleThread(FManager.AcquireNewThread);
|
|
end;
|
|
|
|
function TJvMTManager.AcquireThread(Ticket: TMTTicket;
|
|
var Thread: TJvMTSingleThread): Boolean;
|
|
begin
|
|
Result := FManager.AcquireThread(Ticket, TMTThread(Thread));
|
|
end;
|
|
|
|
function TJvMTManager.ActiveThreads: Boolean;
|
|
begin
|
|
Result := FManager.ActiveThreads;
|
|
end;
|
|
|
|
procedure TJvMTManager.Notification(AComponent: TComponent; Operation:
|
|
TOperation);
|
|
begin
|
|
// check if the form is being destroyed
|
|
if (not (csDesigning in ComponentState)) and (Operation = opRemove) and
|
|
(AComponent = Owner) then
|
|
begin
|
|
// form is going down: terminate all threads
|
|
TerminateThreads;
|
|
// and wait until all is well
|
|
WaitThreads;
|
|
end;
|
|
|
|
inherited Notification(AComponent, Operation);
|
|
end;
|
|
|
|
procedure TJvMTManager.ReleaseThread(Ticket: TMTTicket);
|
|
begin
|
|
FManager.ReleaseThread(Ticket);
|
|
end;
|
|
|
|
procedure TJvMTManager.TerminateThreads;
|
|
begin
|
|
FManager.TerminateThreads;
|
|
end;
|
|
|
|
procedure TJvMTManager.WaitThreads;
|
|
begin
|
|
FManager.WaitThreads;
|
|
end;
|
|
|
|
//=== { TJvMTManagedComponent } ==============================================
|
|
|
|
procedure TJvMTManagedComponent.Notification(AComponent: TComponent; Operation:
|
|
TOperation);
|
|
begin
|
|
if (Operation = opRemove) and (AComponent = FManager) then
|
|
FManager := nil; // important during designtime
|
|
|
|
inherited Notification(AComponent, Operation);
|
|
end;
|
|
|
|
procedure TJvMTManagedComponent.SetManager(Value: TJvMTManager);
|
|
begin
|
|
if Assigned(FManager) then
|
|
FManager.RemoveFreeNotification(Self);
|
|
|
|
FManager := Value;
|
|
|
|
if Assigned(FManager) then
|
|
FManager.FreeNotification(Self);
|
|
end;
|
|
|
|
//=== { TJvMTThread } ========================================================
|
|
|
|
destructor TJvMTThread.Destroy;
|
|
begin
|
|
ReleaseThread;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJvMTThread.CheckTerminate;
|
|
begin
|
|
HookThread;
|
|
FThread.CheckTerminate;
|
|
end;
|
|
|
|
function TJvMTThread.GetStatus: TMTThreadStatus;
|
|
begin
|
|
HookThread;
|
|
Result := FThread.Status;
|
|
end;
|
|
|
|
function TJvMTThread.GetTicket: TMTTicket;
|
|
begin
|
|
HookThread;
|
|
Result := FThread.Ticket;
|
|
end;
|
|
|
|
procedure TJvMTThread.HookThread;
|
|
begin
|
|
if FThread = nil then
|
|
begin
|
|
if FManager = nil then
|
|
raise EThread.CreateRes(@RsENoThreadManager);
|
|
|
|
// get the new thread
|
|
FThread := FManager.AcquireNewThread;
|
|
|
|
// hook up the nessesary events
|
|
if Assigned(FOnExecute) then
|
|
FThread.OnExecute := OnIntExecute;
|
|
if Assigned(FOnTerminating) then
|
|
FThread.OnTerminating := OnIntTerminating;
|
|
if Assigned(FOnFinished) then
|
|
FThread.OnFinished := OnIntFinished;
|
|
|
|
// give it a name
|
|
FThread.Name := Name;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvMTThread.Notification(AComponent: TComponent; Operation:
|
|
TOperation);
|
|
begin
|
|
if (Operation = opRemove) and (AComponent = FManager) then
|
|
ReleaseThread; // important during runtime
|
|
|
|
// now can inherited (this wil invalidate FManager)
|
|
inherited Notification(AComponent, Operation);
|
|
end;
|
|
|
|
procedure TJvMTThread.OnIntExecute(Thread: TMTThread);
|
|
begin
|
|
DoExecute(TJvMTSingleThread(Thread));
|
|
end;
|
|
|
|
procedure TJvMTThread.OnIntFinished(Thread: TMTThread);
|
|
begin
|
|
DoFinished(TJvMTSingleThread(Thread));
|
|
end;
|
|
|
|
procedure TJvMTThread.OnIntTerminating(Thread: TMTThread);
|
|
begin
|
|
DoTerminating(TJvMTSingleThread(Thread));
|
|
end;
|
|
|
|
procedure TJvMTThread.ReleaseThread;
|
|
begin
|
|
// check if there is an acquired thread
|
|
if FThread <> nil then
|
|
begin
|
|
// release the thread and invalidate the pointer
|
|
FThread.Release;
|
|
FThread := nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TJvMTThread.Run;
|
|
begin
|
|
HookThread;
|
|
FThread.Run;
|
|
end;
|
|
|
|
procedure TJvMTThread.RunCopy;
|
|
begin
|
|
ReleaseThread;
|
|
Run;
|
|
end;
|
|
|
|
procedure TJvMTThread.SetManager(Value: TJvMTManager);
|
|
begin
|
|
UnHookThread;
|
|
inherited SetManager(Value);
|
|
end;
|
|
|
|
procedure TJvMTThread.SetOnExecute(Value: TJvMTThreadEvent);
|
|
begin
|
|
UnHookThread;
|
|
FOnExecute := Value;
|
|
end;
|
|
|
|
procedure TJvMTThread.SetOnFinished(Value: TJvMTThreadEvent);
|
|
begin
|
|
UnHookThread;
|
|
FOnFinished := Value;
|
|
end;
|
|
|
|
procedure TJvMTThread.SetOnTerminating(Value: TJvMTThreadEvent);
|
|
begin
|
|
UnHookThread;
|
|
FOnTerminating := Value;
|
|
end;
|
|
|
|
procedure TJvMTThread.Synchronize(Method: TThreadMethod);
|
|
begin
|
|
HookThread;
|
|
FThread.Synchronize(Method);
|
|
end;
|
|
|
|
procedure TJvMTThread.Terminate;
|
|
begin
|
|
HookThread;
|
|
FThread.Terminate;
|
|
end;
|
|
|
|
procedure TJvMTThread.UnHookThread;
|
|
begin
|
|
if FThread <> nil then
|
|
begin
|
|
if FThread.Status in [tsInitializing, tsFinished] then
|
|
begin
|
|
FThread.Terminate; {incase initializing}
|
|
FThread.Release;
|
|
FThread := nil;
|
|
end
|
|
else
|
|
raise EThread.CreateRes(@RsEOperatorNotAvailable);
|
|
end;
|
|
end;
|
|
|
|
procedure TJvMTThread.Wait;
|
|
begin
|
|
HookThread;
|
|
FThread.Wait;
|
|
end;
|
|
|
|
procedure TJvMTThread.DoExecute(MTThread: TJvMTSingleThread);
|
|
begin
|
|
if Assigned(FOnExecute) then
|
|
FOnExecute(Self, MTThread);
|
|
end;
|
|
|
|
procedure TJvMTThread.DoFinished(MTThread: TJvMTSingleThread);
|
|
begin
|
|
if Assigned(FOnFinished) then
|
|
FOnFinished(Self, MTThread);
|
|
end;
|
|
|
|
procedure TJvMTThread.DoTerminating(MTThread: TJvMTSingleThread);
|
|
begin
|
|
if Assigned(FOnTerminating) then
|
|
FOnTerminating(Self, MTThread);
|
|
end;
|
|
|
|
procedure TJvMTThread.Loaded;
|
|
begin
|
|
inherited Loaded;
|
|
// Component is ready. Shall we start a thread?
|
|
if (not (csDesigning in ComponentState)) and FRunOnCreate then
|
|
Run;
|
|
end;
|
|
|
|
//=== { TJvMTSectionBase } ===================================================
|
|
|
|
destructor TJvMTSectionBase.Destroy;
|
|
begin
|
|
// signal interested components that we are going down
|
|
inherited Destroy;
|
|
// cleanup
|
|
FSync.Free;
|
|
end;
|
|
|
|
procedure TJvMTSectionBase.CheckInactiveProperty;
|
|
begin
|
|
if Active then
|
|
raise EThread.CreateRes(@RsECannotChangePropertySection);
|
|
end;
|
|
|
|
procedure TJvMTSectionBase.Enter;
|
|
begin
|
|
HookSync;
|
|
FSync.Acquire;
|
|
end;
|
|
|
|
function TJvMTSectionBase.GetActive: Boolean;
|
|
begin
|
|
Result := FSync <> nil;
|
|
end;
|
|
|
|
procedure TJvMTSectionBase.HookSync;
|
|
begin
|
|
if not Active then
|
|
CreateSync;
|
|
end;
|
|
|
|
procedure TJvMTSectionBase.Leave;
|
|
begin
|
|
HookSync;
|
|
FSync.Release;
|
|
end;
|
|
|
|
//=== { TJvMTSection } =======================================================
|
|
|
|
constructor TJvMTSection.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FAllowRecursion := True;
|
|
end;
|
|
|
|
procedure TJvMTSection.CreateSync;
|
|
begin
|
|
if FAllowRecursion then
|
|
FSync := TMTCriticalSection.Create(Name)
|
|
else
|
|
FSync := TMTMutex.Create(Name);
|
|
|
|
if FInitEntered then
|
|
Enter;
|
|
end;
|
|
|
|
procedure TJvMTSection.SetAllowRecursion(Value: Boolean);
|
|
begin
|
|
CheckInactiveProperty;
|
|
FAllowRecursion := Value;
|
|
end;
|
|
|
|
procedure TJvMTSection.SetInitEntered(Value: Boolean);
|
|
begin
|
|
CheckInactiveProperty;
|
|
FInitEntered := Value;
|
|
end;
|
|
|
|
//=== { TJvMTCountingSection } ===============================================
|
|
|
|
constructor TJvMTCountingSection.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FMaxCount := 1;
|
|
end;
|
|
|
|
procedure TJvMTCountingSection.CreateSync;
|
|
begin
|
|
FSync := TMTSemaphore.Create(FMaxCount-FInitCount, FMaxCount, Name);
|
|
end;
|
|
|
|
procedure TJvMTCountingSection.SetInitAndMax(Init,Max: Integer);
|
|
begin
|
|
CheckInactiveProperty;
|
|
if (Max < 1) or (Init < 0) or (Init > Max) then
|
|
raise EInvalidOperation.CreateResFmt(@SPropertyOutOfRange, [ClassName]);
|
|
|
|
FInitCount := Init;
|
|
FMaxCount := Max;
|
|
end;
|
|
|
|
procedure TJvMTCountingSection.SetInitCount(Value: Integer);
|
|
begin
|
|
SetInitAndMax(Value, FMaxCount);
|
|
end;
|
|
|
|
procedure TJvMTCountingSection.SetMaxCount(Value: Integer);
|
|
begin
|
|
SetInitAndMax(FInitCount, Value);
|
|
end;
|
|
|
|
//=== { TJvMTAsyncBufferBase } ===============================================
|
|
|
|
constructor TJvMTAsyncBufferBase.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FMaxBufferSize := MTDefaultBufferSize;
|
|
FHooking := TCriticalSection.Create;
|
|
end;
|
|
|
|
destructor TJvMTAsyncBufferBase.Destroy;
|
|
begin
|
|
// notify interested components
|
|
inherited Destroy;
|
|
// cleanup
|
|
FBuffer.Free;
|
|
FHooking.Free;
|
|
end;
|
|
|
|
procedure TJvMTAsyncBufferBase.HookBuffer;
|
|
begin
|
|
// buffer still uncreated?
|
|
if FBuffer = nil then
|
|
begin
|
|
// enter critical section
|
|
FHooking.Enter;
|
|
try
|
|
// perform check again. and create if we are the first in this section
|
|
if FBuffer = nil then
|
|
CreateBuffer;
|
|
finally
|
|
FHooking.Leave;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJvMTAsyncBufferBase.Read: TObject;
|
|
begin
|
|
HookBuffer;
|
|
Result := FBuffer.Read;
|
|
end;
|
|
|
|
procedure TJvMTAsyncBufferBase.SetMaxBufferSize(Value: Integer);
|
|
begin
|
|
if FBuffer <> nil then
|
|
raise EThread.CreateRes(@RsECannotChangePropertyBuffer);
|
|
FMaxBufferSize := Value;
|
|
end;
|
|
|
|
procedure TJvMTAsyncBufferBase.Write(AObject: TObject);
|
|
begin
|
|
HookBuffer;
|
|
FBuffer.Write(AObject);
|
|
end;
|
|
|
|
//=== { TJvMTThreadToVCL } ===================================================
|
|
|
|
procedure TJvMTThreadToVCL.CreateBuffer;
|
|
begin
|
|
FBuffer := TMTBufferToVCL.Create(FMaxBufferSize, Name);
|
|
TMTBufferToVCL(FBuffer).OnCanRead := DoCanRead;
|
|
end;
|
|
|
|
procedure TJvMTThreadToVCL.DoCanRead(Sender: TObject);
|
|
begin
|
|
// call the OnCanRead event with this object as the sender
|
|
if Assigned(FOnCanRead) then
|
|
FOnCanRead(Self);
|
|
end;
|
|
|
|
//=== { TJvMTVCLToThread } ===================================================
|
|
|
|
procedure TJvMTVCLToThread.CreateBuffer;
|
|
begin
|
|
FBuffer := TMTVCLToBuffer.Create(FMaxBufferSize, Name);
|
|
TMTVCLToBuffer(FBuffer).OnCanWrite := DoCanWrite;
|
|
end;
|
|
|
|
procedure TJvMTVCLToThread.DoCanWrite(Sender: TObject);
|
|
begin
|
|
// call the OnCanWrite event with this object as the sender
|
|
if Assigned(FOnCanWrite) then
|
|
FOnCanWrite(Self);
|
|
end;
|
|
|
|
procedure TJvMTVCLToThread.Loaded;
|
|
begin
|
|
inherited Loaded;
|
|
// force first Event
|
|
HookBuffer;
|
|
if Assigned(FOnCanWrite) then
|
|
FOnCanWrite(Self);
|
|
end;
|
|
|
|
//=== { TJvMTThreadToThread } ================================================
|
|
|
|
constructor TJvMTThreadToThread.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FMaxBufferSize := MTDefaultBufferSize;
|
|
FHooking := TCriticalSection.Create;
|
|
end;
|
|
|
|
destructor TJvMTThreadToThread.Destroy;
|
|
begin
|
|
inherited Destroy;
|
|
FQueue.Free;
|
|
FHooking.Free;
|
|
end;
|
|
|
|
procedure TJvMTThreadToThread.HookQueue;
|
|
begin
|
|
// buffer still uncreated?
|
|
if FQueue = nil then
|
|
begin
|
|
// enter critical section
|
|
FHooking.Enter;
|
|
try
|
|
// perform check again. and create if we are the first in this section
|
|
if FQueue = nil then
|
|
FQueue := TMTBoundedQueue.Create(FMaxBufferSize,Name);
|
|
finally
|
|
FHooking.Leave;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TJvMTThreadToThread.Read: TObject;
|
|
begin
|
|
HookQueue;
|
|
Result := FQueue.Pop;
|
|
end;
|
|
|
|
procedure TJvMTThreadToThread.SetMaxBufferSize(Value: Integer);
|
|
begin
|
|
if FQueue <> nil then
|
|
raise EThread.CreateRes(@RsECannotChangePropertyBuffer);
|
|
if Value < 1 then
|
|
raise EInvalidOperation.CreateResFmt(@SPropertyOutOfRange, [ClassName]);
|
|
FMaxBufferSize := Value;
|
|
end;
|
|
|
|
procedure TJvMTThreadToThread.Write(AObject: TObject);
|
|
begin
|
|
HookQueue;
|
|
FQueue.Push(AObject);
|
|
end;
|
|
|
|
//=== { TJvMTMonitorSection } ================================================
|
|
|
|
constructor TJvMTMonitorSection.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FMonitor := TMTMonitor.Create;
|
|
end;
|
|
|
|
destructor TJvMTMonitorSection.Destroy;
|
|
begin
|
|
FMonitor.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TJvMTMonitorSection.Enter;
|
|
begin
|
|
FMonitor.Enter;
|
|
end;
|
|
|
|
function TJvMTMonitorSection.GetCondition(ID: Integer): TMTCondition;
|
|
begin
|
|
Result := FMonitor.Condition[ID];
|
|
end;
|
|
|
|
procedure TJvMTMonitorSection.Leave;
|
|
begin
|
|
FMonitor.Leave;
|
|
end;
|
|
|
|
{$IFDEF USEJVCL}
|
|
{$IFDEF UNITVERSIONING}
|
|
initialization
|
|
RegisterUnitVersion(HInstance, UnitVersioning);
|
|
|
|
finalization
|
|
UnregisterUnitVersion(HInstance);
|
|
{$ENDIF UNITVERSIONING}
|
|
{$ENDIF USEJVCL}
|
|
|
|
end.
|