📄 xpwinsync.pas
字号:
unit XPWinSync;
{
$Source: /cvsroot/dunit/dunit/Contrib/DUnitWizard/Source/Common/XPWinSync.pas,v $
$Revision: 1.1 $
$Date: 2004/05/03 15:07:15 $
Last amended by $Author: pvspain $
$State: Exp $
XPWinSync:
Interfaces and implementing classes which wrap Windows
synchronisation mechanisms:
Events (AutoReset and Manual)
Mutexes
Semaphores
CriticalSections
SharedCounters
RWSynchronisers
Copyright (c) 2001 by The Excellent Programming Company Pty Ltd
(Australia) (ABN 27 005 394 918).
Contact Paul Spain via email: paul@xpro.com.au
This unit is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This unit 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this unit; if not, the license can be viewed at:
http://www.gnu.org/copyleft/lesser.html
or write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
}
interface
uses
XPWinBase,
XPRestore, // IXPRestore, TXPRestore
XPSyncRW, // IXPSyncRW
Windows, // THandle, CreateXXX(), OpenXXX
SysUtils; // Exception, Trim(), FmtStr(), AnsiPos(),
// AnsiLowerCase()
type
{$IFDEF XPW32E}
EXPWin32Event = class (EXPWin32) end;
EXPWin32Synchro = class (EXPWin32) end;
EXPWin32Mutex = class (EXPWin32Synchro) end;
EXPWin32Semaphore = class (EXPWin32Synchro) end;
EXPWin32SharedCounter = class (EXPWin32) end;
EXPWin32SerialAccess = class (EXPWin32) end;
{$ENDIF}
//////////////////////////////////////////////////////////////////////////////
/// IXPWinXXXEvent
//////////////////////////////////////////////////////////////////////////////
IXPWinEvent = interface(IXPWinNamedKernelObject)
['{832555D0-0C82-11D5-A261-00608CF441D9}']
// Behaviour of Signal is the prime difference between Auto and Manual
// events. For Auto events, Signal will signal (only) the first waiting
// thread and reset itself. For Manual events, Signal will stay signalled
// until Reset is called
procedure Signal;
end;
IXPWinAutoEvent = interface(IXPWinEvent)
['{7F4EBC21-16E6-11D5-A271-00608CF441D9}']
end;
IXPWinManualEvent = interface(IXPWinEvent)
['{88C4F111-1500-11D5-A26D-00608CF441D9}']
procedure Reset;
// Pulse behaves like Signal for an Auto event, except that it signals
// _all_ waiting threads (not just the first thread) before resetting
// itself.
procedure Pulse;
end;
//////////////////////////////////////////////////////////////////////////////
/// IXPSynchro: Mutexes, semaphores and critical sections
//////////////////////////////////////////////////////////////////////////////
IXPWinSynchro = interface(IXPWinError)
['{7F4EBC22-16E6-11D5-A271-00608CF441D9}']
function Enter: boolean;
function Leave: boolean;
end;
TXPWinSerialAccess = class(TXPWinError, IXPRestore)
private
FSync: IXPWinSynchro;
public
constructor Create(const ASync: IXPWinSynchro);
destructor Destroy; override;
end;
//////////////////////////////////////////////////////////////////////////////
/// IXPWinMutex
//////////////////////////////////////////////////////////////////////////////
IXPWinMutex = interface(IXPWinNamedKernelObject)
['{BC7BDA82-4151-11D5-A2C1-00608CF441D9}']
end;
//////////////////////////////////////////////////////////////////////////////
/// IXPWinXXXSemaphore
//////////////////////////////////////////////////////////////////////////////
IXPWinSemaphore = interface(IXPWinNamedKernelObject)
['{F65C8F71-1700-11D5-A271-00608CF441D9}']
// Count is number of free entries, not occupied entries
//
// There are some caveats on usage of GetCount, as Windows does
// not provide the facility to retrieve the current count value. The
// previous Count value can be retrieved via successful calls to
// Windows.ReleaseSemaphore()
// Caveats:
// GetCount is always accurate for a single-handle semaphore kernel object
// ie a semaphore which has (only) been created, not opened (see
// IXPWinNamedKernelObject.Instance) and which has been manipulated only
// by the interface methods, not via Windows API calls on the handle.
// If the semaphore has more than one handle opened, the count value is only
// guaranteed correct immediately following IXPSynchro.Leave and
// IXPWinSemaphore.Release calls.
// Note that this and the following interface are thread-safe, so the
// interfaces can be passed among threads rather than creating new handles
// via calls to GetSemaphore().
function GetCount: integer;
function Acquire: boolean;
procedure Release;
property Count: integer read GetCount;
end;
// This interface can be used when the semaphore has been created rather than
// opened, ie when Instance = koCreated (IXPWinNamedKernelObject.Instance)
IXPWinCreatedSemaphore = interface(IXPWinSemaphore)
['{64F2B390-26F8-11D5-8CAD-0080ADB62643}']
function GetCapacity: integer;
// Use Open as the first call on a new interface which has been created via
// GetSemaphore() with the CreateOpen parameter as false. This scenario is
// useful to initialize resources upon creation, before releasing them for
// use.
function Open: boolean;
property Capacity: integer read GetCapacity;
end;
//////////////////////////////////////////////////////////////////////////////
/// IXPSharedCounter
//////////////////////////////////////////////////////////////////////////////
const
XPCounterError = System.Low(integer);
type
IXPSharedCounter = interface
['{BC7BDA81-4151-11D5-A2C1-00608CF441D9}']
function GetValue: integer;
procedure SetValue(const Value: integer);
function Inc(const Delta: integer = 1): integer;
function Dec(const Delta: integer = 1): integer;
property Value: integer read GetValue write SetValue;
end;
//////////////////////////////////////////////////////////////////////////////
/// Creator functions: unit entry points
//////////////////////////////////////////////////////////////////////////////
function GetAutoEvent(const CreateAsSignaled: boolean = false;
const AName: string = '';
const Inheritable: boolean = true;
const SecurityDescriptor: Pointer = nil): IXPWinAutoEvent;
function GetManualEvent(const CreateAsSignaled: boolean = false;
const AName: string = '';
const Inheritable: boolean = true;
const SecurityDescriptor: Pointer = nil): IXPWinManualEvent;
{ Mutexes and Semaphores must be instantiated at a scope which is *local* to
each interested thread. The common Name value ensures we are connecting
with the same kernel object. }
function GetMutex(const AName: string = ''; const Inheritable: boolean = true;
const SecurityDescriptor: Pointer = nil): IXPWinMutex;
function GetSemaphore(const Capacity: integer; const AName: string = '';
const CreateOpen: boolean = true; const Inheritable: boolean = true;
const SecurityDescriptor: Pointer = nil): IXPWinSemaphore;
{ Critical sections must be instantiated at a scope which is common to all
interested threads, ie at process *global* scope. }
function CreateCriticalSection: IXPWinSynchro;
function GetSharedCounter(const InitialValue: integer = 0;
const AName: string = ''; const Inheritable: boolean = true;
const SecurityDescriptor: Pointer = nil): IXPSharedCounter;
{ CreateThreadIXPSyncRW creates an interface for intra-process thread
synchronisation. }
function CreateThreadRWSynchroniser(
const SyncPriority: TXPSyncPriority = spReaders): IXPSyncRW;
{ CreateProcessIXPSyncRW creates an interface for inter-process thread
synchronisation. }
function GetProcessRWSynchroniser(const Name: string = '';
const SyncPriority: TXPSyncPriority = spReaders;
const Inheritable: boolean = true;
const SecurityDescriptor: Pointer = nil): IXPSyncRW;
implementation
const CVSID: string = '$Header: /cvsroot/dunit/dunit/Contrib/DUnitWizard/Source/Common/XPWinSync.pas,v 1.1 2004/05/03 15:07:15 pvspain Exp $';
///////////////////////////////////////////////////////////////////////////////
/// TXPSerialAccess implementation
///////////////////////////////////////////////////////////////////////////////
constructor TXPWinSerialAccess.Create(const ASync: IXPWinSynchro);
begin
{$IFDEF XPW32E}
inherited Create(EXPWin32SerialAccess);
{$ELSE}
inherited Create;
{$ENDIF}
FSync := ASync;
if not FSync.Enter then
Error('TXPSerialAccess.Create');
end;
destructor TXPWinSerialAccess.Destroy;
begin
if not FSync.Leave then
Error('TXPSerialAccess.Destroy');
inherited;
end;
///////////////////////////////////////////////////////////////////////////////
/// IXPWinXXXEvent implementation
///////////////////////////////////////////////////////////////////////////////
type
TXPWinEvent = class(TXPWinNamedKernelObject, IXPWinEvent)
private
//
// IXPWinEvent implementation
//
procedure Signal;
public
constructor Create(const AName: string; const CreateAsSignaled: boolean;
const ManualReset: boolean; const Inheritable: boolean;
const SecurityDescriptor: Pointer);
end;
TXPWinAutoEvent = class(TXPWinEvent, IXPWinAutoEvent)
public
constructor Create(const AName: string; const CreateAsSignaled: boolean;
const Inheritable: boolean; const SecurityDescriptor: Pointer);
end;
TXPWinManualEvent = class(TXPWinEvent, IXPWinManualEvent)
private
//
// IXPWinManualEvent implementation
//
procedure Reset;
procedure Pulse;
public
constructor Create(const AName: string; const CreateAsSignaled: boolean;
const Inheritable: boolean; const SecurityDescriptor: Pointer);
end;
constructor TXPWinEvent.Create(const AName: string;
const CreateAsSignaled: boolean; const ManualReset: boolean;
const Inheritable: boolean; const SecurityDescriptor: Pointer);
begin
inherited Create(AName, Inheritable, SecurityDescriptor);
{$IFDEF XPW32E}
SetException(EXPWin32Event);
{$ENDIF}
FHandle := Windows.CreateEvent(@FSecurityAttributes, ManualReset,
CreateAsSignaled, PChar(GetName));
if FHandle = 0 then
Error('TXPWinEvent.Create: Windows.CreateEvent failure')
else if Windows.GetLastError = 0 then
FInstance := koCreated
else if Windows.GetLastError = ERROR_ALREADY_EXISTS then
FInstance := koOpened;
end;
procedure TXPWinEvent.Signal;
begin
Windows.SetEvent(FHandle);
end;
{ TXPWinAutoEvent }
constructor TXPWinAutoEvent.Create(const AName: string;
const CreateAsSignaled: boolean; const Inheritable: boolean;
const SecurityDescriptor: Pointer);
const
ManualReset = false;
begin
inherited Create(AName, CreateAsSignaled, ManualReset, Inheritable,
SecurityDescriptor);
end;
{ TXPWinManualEvent }
constructor TXPWinManualEvent.Create(const AName: string;
const CreateAsSignaled: boolean; const Inheritable: boolean;
const SecurityDescriptor: Pointer);
const
ManualReset = true;
begin
inherited Create(AName, CreateAsSignaled, ManualReset, Inheritable,
SecurityDescriptor);
end;
procedure TXPWinManualEvent.Pulse;
begin
Windows.PulseEvent(GetHandle);
end;
procedure TXPWinManualEvent.Reset;
begin
Windows.ResetEvent(GetHandle);
end;
//////////////////////////////////////////////////////////////////////////////
/// TXPWinMutex implementation
//////////////////////////////////////////////////////////////////////////////
type
TXPWinMutex = class(TXPWinNamedKernelObject, IXPWinMutex, IXPWinSynchro)
private
//
// IXPSynchro implementation
//
function Enter: boolean;
function Leave: boolean;
public
constructor Create(const AName: string; const Inheritable: boolean;
const SecurityDescriptor: Pointer);
end;
constructor TXPWinMutex.Create(const AName: string; const Inheritable: boolean;
const SecurityDescriptor: Pointer);
const
EnterOnCreate = false;
begin
inherited Create(AName, Inheritable, SecurityDescriptor);
{$IFDEF XPW32E}
SetException(EXPWin32Mutex);
{$ENDIF}
FHandle := Windows.CreateMutex(@FSecurityAttributes, EnterOnCreate,
PChar(GetName));
if FHandle = 0 then
Error('TXPWinMutex.Create: Windows.CreateMutex failure')
else if Windows.GetLastError = 0 then
FInstance := koCreated
else if Windows.GetLastError = ERROR_ALREADY_EXISTS then
FInstance := koOpened;
end;
function TXPWinMutex.Enter: boolean;
begin
Result := Wait;
if not Result then
SetLastContext('TXPWinMutex.Enter: ' + GetLastContext);
end;
function TXPWinMutex.Leave: boolean;
begin
Result := Windows.ReleaseMutex(FHandle);
if not Result then
Error('TXPWinMutex.Leave: Windows.ReleaseMutex failure');
end;
//////////////////////////////////////////////////////////////////////////////
/// TXPWinSemaphore implementation
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -