Show: Delphi C++
Display Preferences

System.TMonitor

From XE2 API Documentation
Jump to: navigation, search

Delphi

  TMonitor = record
  strict private
    type
      PWaitingThread = ^TWaitingThread;
      TWaitingThread = record
        Next: PWaitingThread;
        Thread: TThreadID;
        WaitEvent: Pointer;
      end;
      { TSpinWait implements an exponential backoff algorithm for TSpinLock. The algorithm is as follows:
        If the CPUCount > 1, then the first 10 (YieldThreshold) spin cycles (calls to SpinCycle) will use a base 2
        exponentially increasing spin count starting at 4. After 10 cycles, then the behavior reverts to the same
        behavior as when CPUCount = 1.
        If the CPUCount = 1, then it will sleep 1ms every modulus 20 cycles and sleep 0ms every modulus 5 cycles.
        All other cycles simply yield (SwitchToThread - Windows, sched_yield - POSIX). }
      TSpinWait = record
      private const
        YieldThreshold = 10;
        Sleep1Threshold = 20;
        Sleep0Threshold = 5;
      private
        FCount: Integer;
      public
        procedure Reset; inline;
        procedure SpinCycle;
      end;
      { TSpinLock implements a very simple non-reentrant lock. This lock does not block the calling thread using a
        synchronization object. Instead it opts to burn a few extra CPU cycles using the above TSpinWait type. This
        is typically far faster than fully blocking since the length of time the lock is held is relatively few
        cycles and the thread switching overhead will usually far outpace the few cycles burned by simply spin
        waiting. }
      TSpinLock = record
      private
        FLock: Integer;
      public
        procedure Enter;
        procedure Exit;
      end;
    var
      FLockCount: Integer;
      FRecursionCount: Integer;
      FOwningThread: TThreadID;
      FLockEvent: Pointer;
      FSpinCount: Integer;
      FWaitQueue: PWaitingThread;
      FQueueLock: TSpinLock;
    class var CacheLineSize: Integer;
    class procedure Spin(Iterations: Integer); static;
    class function GetCacheLineSize: Integer; static;
    procedure QueueWaiter(var WaitingThread: TWaitingThread);
    procedure RemoveWaiter(var WaitingThread: TWaitingThread);
    function DequeueWaiter: PWaitingThread;
    function GetEvent: Pointer;
    function CheckOwningThread: TThreadID;
    class procedure CheckMonitorSupport; static; inline;
    class function Create: PMonitor; static;
  private
    class procedure Destroy(AObject: TObject); overload; static;
  strict private
    class function GetFieldAddress(AObject: TObject): PPMonitor; inline; static;
    class function GetMonitor(AObject: TObject): PMonitor; static;
    procedure Destroy; overload;
    function Enter(Timeout: Cardinal): Boolean; overload;
    procedure Exit; overload;
    function TryEnter: Boolean; overload;
    function Wait(ALock: PMonitor; Timeout: Cardinal): Boolean; overload;
    procedure Pulse; overload;
    procedure PulseAll; overload;
  public
    { In multi-core/multi-processor systems, it is sometimes desirable to spin for a few cycles instead of blocking
      the current thread when attempting to Enter the monitor. Use SetSpinCount to set a reasonable number of times to
      spin before fully blocking the thread. This value usually obtained through empirical study of the particular
      situation.  }
    class procedure SetSpinCount(AObject: TObject; ASpinCount: Integer); static;
    { Enter locks the monitor object with an optional timeout (in ms) value. Enter without a timeout will wait until
      the lock is obtained. If the procedure returns it can be assumed that the lock was acquired. Enter with a
      timeout will return a boolean status indicating whether or not the lock was obtained (True) or the attempt timed
      out prior to acquire the lock (False). Calling Enter with an INFINITE timeout is the same as calling Enter
      without a timeout.
      TryEnter will simply attempt to obtain the lock and return immediately whether or not the lock was acuired.
      Enter with a 0ms timeout is functionally equivalent to TryEnter.
      Exit will potentially release the lock acquired by a call to Enter or TryEnter. Since Enter/TryEnter are
      rentrant, you must balance each of those calls with a corresponding call to Exit. Only the last call to Exit will
      release the lock and allow other threads to obtain it. Runtime error, reMonitorNoLocked, is generated if Exit is
      called and the calling thread does not own the lock. }
    class procedure Enter(AObject: TObject); overload; static; inline;
    class function Enter(AObject: TObject; Timeout: Cardinal): Boolean; overload; static;
    class procedure Exit(AObject: TObject); overload; static;
    class function TryEnter(AObject: TObject): Boolean; overload; static;
    { Wait will atomically fully release the lock (regardless of the recursion count) and block the calling thread
      until another thread calls Pulse or PulseAll. The first overloaded Wait function will assume the locked object
      and wait object are the same and thus the calling thread must own the lock. The second Wait allows the given

C++

struct DECLSPEC_DRECORD TMonitor{
private:
struct TWaitingThread;
typedef TWaitingThread *PWaitingThread;
struct DECLSPEC_DRECORD TWaitingThread
{
public:
TMonitor::TWaitingThread *Next;
unsigned Thread;
void *WaitEvent;
};
struct DECLSPEC_DRECORD TSpinWait
{
private:
static const System::Int8 YieldThreshold = System::Int8(0xa);
static const System::Int8 Sleep1Threshold = System::Int8(0x14);
static const System::Int8 Sleep0Threshold = System::Int8(0x5);
int FCount;
public:
void __fastcall Reset(void);
void __fastcall SpinCycle(void);
};
struct DECLSPEC_DRECORD TSpinLock
{
private:
int FLock;
public:
void __fastcall Enter(void);
void __fastcall Exit(void);
};
private:
int FLockCount;
int FRecursionCount;
unsigned FOwningThread;
void *FLockEvent;
int FSpinCount;
TWaitingThread *FWaitQueue;
TSpinLock FQueueLock;
static int CacheLineSize;
static void __fastcall Spin(int Iterations);
static int __fastcall GetCacheLineSize();
void __fastcall QueueWaiter(TWaitingThread &WaitingThread);
void __fastcall RemoveWaiter(TWaitingThread &WaitingThread);
PWaitingThread __fastcall DequeueWaiter(void);
void * __fastcall GetEvent(void);
unsigned __fastcall CheckOwningThread(void);
static void __fastcall CheckMonitorSupport();
static PMonitor __fastcall Create();
private:
static void __fastcall Destroy(TObject* AObject)/* overload */;
private:
static PPMonitor __fastcall GetFieldAddress(TObject* AObject);
static PMonitor __fastcall GetMonitor(TObject* AObject);
void __fastcall Destroy(void)/* overload */;
bool __fastcall Enter(unsigned Timeout)/* overload */;
void __fastcall Exit(void)/* overload */;
bool __fastcall TryEnter(void)/* overload */;
bool __fastcall Wait(PMonitor ALock, unsigned Timeout)/* overload */;
void __fastcall Pulse(void)/* overload */;
void __fastcall PulseAll(void)/* overload */;
public:
static void __fastcall SetSpinCount(TObject* AObject, int ASpinCount);
static void __fastcall Enter(TObject* AObject)/* overload */;
static bool __fastcall Enter(TObject* AObject, unsigned Timeout)/* overload */;
static void __fastcall Exit(TObject* AObject)/* overload */;
static bool __fastcall TryEnter(TObject* AObject)/* overload */;
static bool __fastcall Wait(TObject* AObject, unsigned Timeout)/* overload */;
static bool __fastcall Wait(TObject* AObject, TObject* ALock, unsigned Timeout)/* overload */;
static void __fastcall Pulse(TObject* AObject)/* overload */;
static void __fastcall PulseAll(TObject* AObject)/* overload */;
};

Properties

Type Visibility Source Unit Parent
struct
class
public
System.pas
System.hpp
System System

Description

TMonitor provides methods for synchronizing the access of several threads to a single object.

Use the class methods of TMonitor to synchronize the threads' access to resources in a multithreaded application.

See Also

Personal tools
Previous Versions
Translations