mormot.core.os--TSynLocker和TSynLocked

打印 上一主题 下一主题

主题 850|帖子 850|积分 2550

mormot.core.os--TSynLocker和TSynLocked

TLightLock
  1. { **************** TSynLocker/TSynLocked 和 低级线程特性 }
  2. type
  3.   /// 一个轻量级的独占非重入锁,存储在 PtrUInt 值中
  4.   // - 在自旋一段时间后调用 SwitchToThread,但不使用任何读写操作系统API
  5.   // - 警告:方法是非重入的,即在一个裸调用中两次调用 Lock 会导致死锁:
  6.   //   对于需要重入方法的情况,请使用 TRWLock 或 TSynLocker/TOSLock
  7.   // - 多个轻量级锁,每个保护少量变量(如列表),可能比更全局的 TOSLock/TRWLock 更高效
  8.   // - 我们的轻量级锁预计保持时间非常短(几个CPU周期):
  9.   //   如果锁可能阻塞太长时间,请使用 TSynLocker 或 TOSLock
  10.   // - TryLock/UnLock 可用于线程安全地获取共享资源
  11.   // - 在 CPU32 上占用 4 字节,在 CPU64 上占用 8 字节
  12.   {$ifdef USERECORDWITHMETHODS}
  13.   TLightLock = record
  14.   {$else}
  15.   TLightLock = object
  16.   {$endif USERECORDWITHMETHODS}
  17.   private
  18.     Flags: PtrUInt; // 标志位
  19.     // 由 Lock 方法在内联时调用的低级函数
  20.     procedure LockSpin;
  21.   public
  22.     /// 如果实例未被初始化为 0,则调用此方法
  23.     // - 例如,如果 TLightLock 被定义为类字段,则不需要此方法
  24.     procedure Init;
  25.       {$ifdef HASINLINE} inline; {$endif}
  26.   
  27.     /// 可用于将实例作为 TOSLock 进行终结处理
  28.     // - 不执行任何操作 - 仅与 TOSLock 兼容
  29.     procedure Done;
  30.       {$ifdef HASINLINE} inline; {$endif}
  31.   
  32.     /// 进入独占非重入锁
  33.     procedure Lock;
  34.       {$ifdef HASINLINE} inline; {$endif}
  35.   
  36.     /// 尝试进入独占非重入锁
  37.     // - 如果返回 true,则调用者最终应调用 UnLock()
  38.     // - 也可用于线程安全地获取共享资源
  39.     function TryLock: boolean;
  40.       {$ifdef HASINLINE} inline; {$endif}
  41.   
  42.     /// 检查独占非重入锁是否已被获取
  43.     function IsLocked: boolean;
  44.       {$ifdef HASINLINE} inline; {$endif}
  45.   
  46.     /// 离开独占非重入锁
  47.     procedure UnLock;
  48.       {$ifdef HASINLINE} inline; {$endif}
  49.   end;
复制代码
TRWLightLock
  1.   /// 一个轻量级的支持多个读操作/独占写操作的非升级锁
  2.   // - 在自旋一段时间后调用 SwitchToThread,但不使用任何读写操作系统API
  3.   // - 警告:读锁是可重入的并允许并发访问,但在读锁内部或另一个写锁内部调用 WriteLock 会导致死锁
  4.   // - 如果您需要一个可升级的锁,请考虑使用 TRWLock - 但对于大多数读操作,
  5.   //   TRWLightLock.ReadLock/ReadUnLock/WriteLock 模式比升级更快
  6.   // - 我们的轻量级锁预计保持时间非常短(几个CPU周期):
  7.   //   如果锁可能阻塞太长时间,请使用 TSynLocker 或 TOSLock
  8.   // - 多个轻量级锁,每个保护少量变量(如列表),可能比更全局的 TOSLock/TRWLock 更高效
  9.   // - 在 CPU32 上占用 4 字节,在 CPU64 上占用 8 字节
  10.   {$ifdef USERECORDWITHMETHODS}
  11.   TRWLightLock = record
  12.   {$else}
  13.   TRWLightLock = object
  14.   {$endif USERECORDWITHMETHODS}
  15.   private
  16.     Flags: PtrUInt; // 标志位,位 0 = 写锁,>0 = 读锁计数器
  17.     // 由 Lock 方法在内联时调用的低级函数
  18.     procedure ReadLockSpin;
  19.     procedure WriteLockSpin;
  20.   public
  21.     /// 如果实例未被初始化为 0,则调用此方法
  22.     // - 例如,如果 TRWLightLock 被定义为类字段,则不需要此方法
  23.     procedure Init;
  24.       {$ifdef HASINLINE} inline; {$endif}
  25.   
  26.     /// 进入不可升级的多读锁
  27.     // - 读锁维护一个线程安全的计数器,因此是可重入和非阻塞的
  28.     // - 警告:在读锁之后嵌套调用 WriteLock 会导致死锁
  29.     procedure ReadLock;
  30.       {$ifdef HASINLINE} inline; {$endif}
  31.   
  32.     /// 尝试进入不可升级的多读锁
  33.     // - 如果返回 true,则调用者最终应调用 ReadUnLock
  34.     // - 读锁维护一个线程安全的计数器,因此是可重入和非阻塞的
  35.     // - 警告:在读锁之后嵌套调用 WriteLock 会导致死锁
  36.     function TryReadLock: boolean;
  37.       {$ifdef HASINLINE} inline; {$endif}
  38.   
  39.     /// 离开不可升级的多读锁
  40.     procedure ReadUnLock;
  41.       {$ifdef HASINLINE} inline; {$endif}
  42.   
  43.     /// 进入不可重入且不可升级的独占写锁
  44.     // - 警告:在读锁或另一个写锁之后嵌套调用 WriteLock 会导致死锁
  45.     procedure WriteLock;
  46.       {$ifdef HASINLINE} inline; {$endif}
  47.   
  48.     /// 尝试进入不可重入且不可升级的独占写锁
  49.     // - 如果返回 true,则调用者最终应调用 WriteUnLock
  50.     // - 警告:在读锁或另一个写锁之后嵌套调用 TryWriteLock 会导致死锁
  51.     function TryWriteLock: boolean;
  52.       {$ifdef HASINLINE} inline; {$endif}
  53.   
  54.     /// 离开不可重入且不可升级的独占写锁
  55.     procedure WriteUnLock;
  56.       {$ifdef HASINLINE} inline; {$endif}
  57.   end;
复制代码
TLockedList
  1. /// 指向TLockedList中一个数据条目的指针
  2. PLockedListOne = ^TLockedListOne;
  3. /// TLockedList中一个数据条目的抽象父类,存储两个PLockedListOne指针
  4. // - TLockedList应该存储以这些字段开头的非托管记录
  5. // - sequence字段包含一个递增的、基于随机种子的30位整数(大于65535),
  6. //   以避免实例回收时出现的ABA问题
  7. TLockedListOne = record
  8.     next, prev: pointer;  // 指向下一个和上一个条目的指针
  9.     sequence: PtrUInt;    // 序列号,用于解决ABA问题
  10. end;
  11. /// 用于终结一个TLockedListOne实例的可选回调事件
  12. TOnLockedListOne = procedure(one: PLockedListOne) of object;
  13. /// 线程安全的双链表,包含TLockedListOne后代的回收机制
  14. {$ifdef USERECORDWITHMETHODS}
  15. TLockedList = record
  16. {$else}
  17. TLockedList = object
  18. {$endif USERECORDWITHMETHODS}
  19. private
  20.     fHead, fBin: pointer;  // 分别指向链表头部和回收箱的指针
  21.     fSize: integer;        // 列表中每个实例的大小(包括TLockedListOne头部)
  22.     fSequence: PtrUInt;    // 全局序列号生成器
  23.     fOnFree: TOnLockedListOne; // 当实例被释放时调用的回调
  24. public
  25.     /// 线程安全的访问锁
  26.     Safe: TLightLock;
  27.   
  28.     /// 当前列表中存储的TLockedListOne实例数量(不包括回收箱中的实例)
  29.     Count: integer;
  30.   
  31.     /// 初始化继承自TLockedListOne的大小的存储
  32.     procedure Init(onesize: PtrUInt; const onefree: TOnLockedListOne = nil);
  33.   
  34.     /// 释放所有存储的内存
  35.     procedure Done;
  36.   
  37.     /// 在线程安全的O(1)过程中分配一个新的PLockedListOne数据实例
  38.     function New: pointer;
  39.   
  40.     /// 在线程安全的O(1)过程中释放一个已使用的PLockedListOne数据实例
  41.     function Free(one: pointer): boolean;
  42.   
  43.     /// 释放当前存储在此列表中的所有TLockedListOne实例
  44.     // - 不会将任何实例移动到内部回收箱
  45.     procedure Clear;
  46.   
  47.     /// 释放内部回收箱中所有待回收的项
  48.     // - 返回从内部收集器中释放了多少项
  49.     function EmptyBin: integer;
  50.   
  51.     /// 作为PLockedListOne双链表的原始访问存储的项
  52.     property Head: pointer
  53.       read fHead;
  54.   
  55.     /// 存储的每个实例的大小,包括其TLockedListOne头部
  56.     property Size: integer
  57.       read fSize;
  58. end;
复制代码
TSynLocker
  1. type  
  2.   /// TSynLocker处理线程同步的方式  
  3.   // - 默认情况下,uSharedLock将使用主TRTLCriticalSection  
  4.   // - 您可以设置uRWLock并调用重载的RWLock/RWUnLock()来使用更轻量级的TRWLock - 但请注意,cReadOnly后跟cReadWrite/cWrite会导致死锁 - 常规的Lock/UnLock将使用cWrite独占锁  
  5.   // - uNoLock将禁用整个锁定机制  
  6.   TSynLockerUse = (  
  7.     uSharedLock,  
  8.     uRWLock,  
  9.     uNoLock);  
  10.   
  11.   /// 允许向任何类实例添加跨平台锁定方法  
  12.   // - 典型用途是定义一个Safe: TSynLocker属性,在构造函数/析构函数方法中调用Safe.Init和Safe.Done,并在try ... finally部分使用Safe.Lock/UnLock方法  
  13.   // - 相对于TCriticalSection类,修复了可能降低多线程性能的CPU缓存行冲突问题,如http://www.delphitools.info/2011/11/30/fixing-tcriticalsection所述  
  14.   // - 内部填充用于安全存储最多7个受互斥锁保护的值,因此SizeOf(TSynLocker)>128  
  15.   // - 对于对象级锁定,请参阅TSynPersistentLock,它拥有一个此类实例,或在构造函数中调用低级fSafe := NewSynLocker,然后在析构函数中调用fSafe^.DoneAndFreemem  
  16.   // - RWUse属性可以将TRTLCriticalSection替换为更轻量级的TRWLock  
  17.   // - 如果多读/独占写锁更合适(仅当锁定过程不会花费太多时间时),请参阅TRWLock和TSynPersistentRWLock  
  18.   {$ifdef USERECORDWITHMETHODS}  
  19.   TSynLocker = record  
  20.   {$else}  
  21.   TSynLocker = object  
  22.   {$endif USERECORDWITHMETHODS}  
  23.   private  
  24.     fSection: TRTLCriticalSection; // 主同步对象  
  25.     fRW: TRWLock; // 可选的读写锁  
  26.     fPaddingUsedCount: byte; // 填充区已使用计数  
  27.     fInitialized: boolean; // 初始化标志  
  28.     fRWUse: TSynLockerUse; // 锁使用模式  
  29.     fLockCount: integer; // 锁计数(用于重入)  
  30.     // 以下为用于安全访问内部填充数据的辅助方法  
  31.     function GetVariant(Index: integer): Variant;  
  32.     procedure SetVariant(Index: integer; const Value: Variant);  
  33.     function GetInt64(Index: integer): Int64;  
  34.     procedure SetInt64(Index: integer; const Value: Int64);  
  35.     function GetBool(Index: integer): boolean;  
  36.     procedure SetBool(Index: integer; const Value: boolean);  
  37.     function GetUnlockedInt64(Index: integer): Int64;  
  38.     procedure SetUnlockedInt64(Index: integer; const Value: Int64);  
  39.     function GetPointer(Index: integer): Pointer;  
  40.     procedure SetPointer(Index: integer; const Value: Pointer);  
  41.     function GetUtf8(Index: integer): RawUtf8;  
  42.     procedure SetUtf8(Index: integer; const Value: RawUtf8);  
  43.     function GetIsLocked: boolean;  
  44.     // - 如果RWUse=uSharedLock,则调用EnterCriticalSection(不支持并行读取)  
  45.     // - 警告:如果RWUse=uRWLock,则此方法将使用内部TRWLock  
  46.     // - 在受保护部分中定义,以便更好地内联并修复Delphi编译器关于uses classes中缺少Windows单元的警告  
  47.     procedure RWLock(context: TRWLockContext);  
  48.       {$ifdef HASINLINE} inline; {$endif}  
  49.     procedure RWUnLock(context: TRWLockContext);  
  50.       {$ifdef HASINLINE} inline; {$endif}  
  51.   public  
  52.     /// 内部填充数据,也用于存储最多7个Variant值  
  53.     // - 这个内存缓冲区将确保不会发生CPU缓存行混合  
  54.     // - 您不应直接使用此字段,而应使用Locked[], LockedInt64[], LockedUtf8[]或LockedPointer[]方法  
  55.     // - 如果您要访问这些数组值,请确保在try ... finally结构中保护它们,并使用Safe.Lock和Safe.Unlock,同时准确维护PaddingUsedCount属性  
  56.     Padding: array[0..6] of TVarData;  
  57.   
  58.     /// 初始化互斥锁  
  59.     // - 调用此方法是强制性的(例如,在拥有TSynLocker实例的类构造函数中),否则您可能会遇到意外的行为,如访问违规或内存泄漏  
  60.     procedure Init;  
  61.    
  62.     /// 终结互斥锁  
  63.     // - 调用此方法是强制性的(例如,在拥有TSynLocker实例的类析构函数中),否则您可能会遇到意外的行为,如访问违规或内存泄漏  
  64.     procedure Done;  
  65.   
  66.     /// 终结互斥锁,并对实例的指针调用FreeMem()  
  67.     // - 应该通过NewSynLocker调用来初始化  
  68.     procedure DoneAndFreeMem;  
  69.   
  70.     /// 低级锁定获取,相当于RWLock(cReadOnly)  
  71.     // - 如果RWUse=uSharedLock,则调用EnterCriticalSection(不支持并行读取)  
  72.     // - 警告:如果RWUse=uRWLock,则嵌套的Lock调用会导致死锁,但嵌套的ReadLock调用不会  
  73.     procedure ReadLock;  
  74.   
  75.     /// 低级锁定释放,相当于RWUnLock(cReadOnly)  
  76.     procedure ReadUnLock;  
  77.   
  78.     /// 低级锁定获取,相当于RWLock(cReadWrite)  
  79.     // - 如果RWUse=uSharedLock,则调用EnterCriticalSection(不支持并行读取)  
  80.     // - 如果RWUse=uRWLock,则嵌套的Lock调用不会导致死锁  
  81.     procedure ReadWriteLock;  
  82.     /// 低级锁定释放,相当于RWUnLock(cReadWrite)  
  83.     procedure ReadWriteUnLock;  
  84.   
  85.     /// 对实例进行独占访问锁定,相当于RWLock(cWrite)  
  86.     // - 从同一线程是可重入的,即您可以嵌套Lock/UnLock调用  
  87.     // - 警告:如果RWUse=uRWLock,则在嵌套ReadLock之后会导致死锁,但在ReadWriteLock之后不会  
  88.     // - 使用此类结构以避免竞态条件(从Safe: TSynLocker属性):  
  89.     // ! Safe.Lock;  
  90.     // ! try  
  91.     // !   ...  
  92.     // ! finally  
  93.     // !   Safe.Unlock;  
  94.     // ! end;  
  95.     procedure Lock;  
  96.   
  97.     /// 尝试获取互斥锁  
  98.     // - 如果RWUse不是默认的uSharedLock,则什么也不做并返回false  
  99.     // - 使用此类结构以避免竞态条件(从Safe: TSynLocker属性):  
  100.     // ! if Safe.TryLock then  
  101.     // !   try  
  102.     // !     ...  
  103.     // !   finally  
  104.     // !     Safe.Unlock;  
  105.     // !   end;  
  106.     function TryLock: boolean;  
  107.   
  108.     /// 尝试在给定的时间内获取互斥锁  
  109.     // - 如果RWUse不是默认的uSharedLock,则只是等待并返回false  
  110.     // - 使用此类结构以避免竞态条件(从Safe: TSynLocker属性):  
  111.     // ! if Safe.TryLockMS(100) then  
  112.     // !   try  
  113.     // !     ...  
  114.     // !   finally  
  115.     // !     Safe.Unlock;  
  116.     // !   end;  
  117.     function TryLockMS(retryms: integer; terminated: PBoolean = nil): boolean;  
  118.   
  119.     /// 释放实例的独占访问权,相当于RWUnLock(cWrite)  
  120.     // - 每个Lock/TryLock调用都应该有一个对应的UnLock调用,因此try..finally块是安全代码所必需的  
  121.     procedure UnLock; overload;  
  122.     /// 将进入互斥锁,直到释放IUnknown引用  
  123.     // - 在Delphi中可以这样使用:  
  124.     // !begin  
  125.     // !  ... // 不安全代码  
  126.     // !  Safe.ProtectMethod;  
  127.     // !  ... // 线程安全代码  
  128.     // !end; // 局部变量隐藏的IUnknown将释放方法的锁  
  129.     // - 警告:在FPC中,您应该将结果分配给局部变量 - 请参阅bug http://bugs.freepascal.org/view.php?id=26602  
  130.     // !var  
  131.     // !  LockFPC: IUnknown;  
  132.     // !begin  
  133.     // !  ... // 不安全代码  
  134.     // !  LockFPC := Safe.ProtectMethod;  
  135.     // !  ... // 线程安全代码  
  136.     // !end; // LockFPC将释放方法的锁  
  137.     // 或  
  138.     // !begin  
  139.     // !  ... // 不安全代码  
  140.     // !  with Safe.ProtectMethod do  
  141.     // !  begin  
  142.     // !    ... // 线程安全代码  
  143.     // !  end; // 局部变量隐藏的IUnknown将释放方法的锁  
  144.     // !end;  
  145.     function ProtectMethod: IUnknown;  
  146.   
  147.     /// 存储在内部Padding[]数组中的值数  
  148.     // - 如果没有存储任何值,则为0,否则为1..7之间的数字  
  149.     // - 您通常不需要使用此字段,但对于在Lock/UnLock安全块内优化对Padding[]值的低级直接访问,它是必要的  
  150.     property PaddingUsedCount: byte  
  151.       read fPaddingUsedCount write fPaddingUsedCount;  
  152.   
  153.     /// 如果互斥锁当前被另一个线程锁定,则返回true  
  154.     // - 如果RWUse=uRWLock,则任何锁(即使是ReadOnlyLock)也会返回true
  155.     property IsLocked: boolean
  156.       read GetIsLocked;
  157.   
  158.     /// 如果已为此互斥锁调用Init方法,则返回true
  159.     // - 仅当整个对象之前已被填充为0时(即作为类的一部分或作为全局变量),这一点才相关,但如果是在堆栈上分配的,则可能不准确
  160.     property IsInitialized: boolean
  161.       read fInitialized;
  162.   
  163.     /// 安全锁定访问Variant值
  164.     // - 您可以存储最多7个变量,使用0..6索引,与LockedBool、LockedInt64、LockedPointer和LockedUtf8数组属性共享
  165.     // - 如果索引超出范围,则返回null
  166.     // - 如果RWUse设置为uRWLock,则允许并发线程读取
  167.     property Locked[Index: integer]: Variant
  168.       read GetVariant write SetVariant;
  169.   
  170.     /// 安全锁定访问Int64值
  171.     // - 您可以存储最多7个变量,使用0..6索引,与Locked和LockedUtf8数组属性共享
  172.     // - Int64将作为varInt64变体内部存储
  173.     // - 如果索引超出范围或不存储Int64,则返回nil
  174.     // - 如果RWUse设置为uRWLock,则允许并发线程读取
  175.     property LockedInt64[Index: integer]: Int64
  176.       read GetInt64 write SetInt64;
  177.   
  178.     /// 安全锁定访问布尔值
  179.     // - 您可以存储最多7个变量,使用0..6索引,与Locked、LockedInt64、LockedPointer和LockedUtf8数组属性共享
  180.     // - 值将作为varboolean变体内部存储
  181.     // - 如果索引超出范围或不存储布尔值,则返回nil
  182.     // - 如果RWUse设置为uRWLock,则允许并发线程读取
  183.     property LockedBool[Index: integer]: boolean
  184.       read GetBool write SetBool;
  185.    
  186.     /// 安全锁定访问指针/TObject值
  187.     // - 您可以存储最多7个变量,使用0..6索引,与Locked、LockedBool、LockedInt64和LockedUtf8数组属性共享
  188.     // - 指针将作为varUnknown变体内部存储
  189.     // - 如果索引超出范围或不存储指针,则返回nil
  190.     // - 如果RWUse设置为uRWLock,则允许并发线程读取
  191.     property LockedPointer[Index: integer]: Pointer
  192.       read GetPointer write SetPointer;
  193.   
  194.     /// 安全锁定访问UTF-8字符串值
  195.     // - 您可以存储最多7个变量,使用0..6索引,与Locked和LockedPointer数组属性共享
  196.     // - UTF-8字符串将作为varString变体内部存储
  197.     // - 如果索引超出范围或不存储字符串,则返回''
  198.     // - 如果RWUse设置为uRWLock,则允许并发线程读取
  199.     property LockedUtf8[Index: integer]: RawUtf8
  200.       read GetUtf8 write SetUtf8;
  201.   
  202.     /// 安全锁定就地递增Int64值
  203.     // - 您可以存储最多7个变量,使用0..6索引,与Locked和LockedUtf8数组属性共享
  204.     // - Int64将作为varInt64变体内部存储
  205.     // - 返回新存储的值
  206.     // - 如果内部值尚未定义,则默认使用0
  207.     function LockedInt64Increment(Index: integer; const Increment: Int64): Int64;
  208.   
  209.     /// 安全锁定就地交换Variant值
  210.     // - 您可以存储最多7个变量,使用0..6索引,与Locked和LockedUtf8数组属性共享
  211.     // - 返回之前存储的值,如果索引超出范围,则返回null
  212.     function LockedExchange(Index: integer; const Value: variant): variant;
  213.   
  214.     /// 安全锁定就地交换指针/TObject值
  215.     // - 您可以存储最多7个变量,使用0..6索引,与Locked和LockedUtf8数组属性共享
  216.     // - 指针将作为varUnknown变体内部存储
  217.     // - 返回之前存储的值,如果索引超出范围或不存储指针,则返回nil
  218.     function LockedPointerExchange(Index: integer; Value: pointer): pointer;
  219.   
  220.     /// 不安全访问Int64值
  221.     // - 您可以存储最多7个变量,使用0..6索引,与Locked和LockedUtf8数组属性共享
  222.     // - Int64将作为varInt64变体内部存储
  223.     // - 如果索引超出范围或不存储Int64,则返回nil
  224.     // - 您应该调用LockedInt64[]属性,或使用此属性并在Lock; try ... finally UnLock块中使用
  225.     property UnlockedInt64[Index: integer]: Int64
  226.       read GetUnlockedInt64 write SetUnlockedInt64;
  227.   
  228.     /// RWLock/RWUnLock的处理方式
  229.     property RWUse: TSynLockerUse
  230.       read fRWUse write fRWUse;
  231.   end;
复制代码
这段代码定义了一个 TSynLocker类型,它允许跨平台地为任何类实例添加锁定方法,以确保线程安全。它提供了多种锁定机制(如共享锁、读写锁和无锁),以及安全访问内部存储的值的方法。这些特性使得 TSynLocker成为处理多线程编程中同步题目的一个强盛工具。
TAutoLock
  1. /// 指向TSynLocker互斥锁实例的指针
  2. // - 另请参见NewSynLocker和TSynLocker.DoneAndFreemem函数
  3. PSynLocker = ^TSynLocker;
  4. /// TAutoLocker.ProtectMethod和TSynLocker.ProtectMethod使用的原始类
  5. // - 在此定义以供mormot.core.data.pas中的TAutoLocker使用
  6. TAutoLock = class(TInterfacedObject)
  7. protected
  8.     fLock: PSynLocker; // 指向TSynLocker的指针
  9. public
  10.     constructor Create(aLock: PSynLocker); // 构造函数,接受一个PSynLocker参数
  11.     destructor Destroy; override; // 析构函数,重写自TInterfacedObject
  12. end;
复制代码
TSynEvent
  1. /// 我们的轻量级跨平台TEvent类似组件
  2. // - 在Windows上,直接调用CreateEvent/ResetEvent/SetEvent API
  3. // - 在Linux上,将使用阻塞和非信号量模式的eventfd()
  4. // - 在其他POSIX系统上,将使用比TEvent BasicEvent更轻的PRTLEvent
  5. // - 唯一限制是我们不知道WaitFor是被信号触发还是超时,
  6. // 但实际上这并不是一个大问题,因为大多数代码不需要这个信息
  7. // 或者已经在其实现逻辑中有了自己的标志
  8. TSynEvent = class
  9. protected
  10.     fHandle: pointer; // Windows THandle或FPC PRTLEvent
  11.     fFD: integer;     // 用于eventfd()
  12. public
  13.     /// 初始化跨平台事件实例
  14.     constructor Create;
  15.     /// 终结跨平台事件实例
  16.     destructor Destroy; override;
  17.     /// 忽略任何挂起的事件,以便WaitFor将在下次SetEvent时被设置
  18.     procedure ResetEvent;
  19.       {$ifdef OSPOSIX} inline; {$endif}
  20.     /// 触发任何挂起的事件,释放WaitFor/WaitForEver方法
  21.     procedure SetEvent;
  22.       {$ifdef OSPOSIX} inline; {$endif}
  23.     /// 等待,直到另一个线程调用SetEvent,具有最大时间
  24.     // - 如果被信号触发或超时,则不返回
  25.     // - 警告:您应该一次只从一个线程等待
  26.     procedure WaitFor(TimeoutMS: integer);
  27.       {$ifdef OSPOSIX} inline; {$endif}
  28.     /// 无限期等待,直到另一个线程调用SetEvent
  29.     procedure WaitForEver;
  30.       {$ifdef OSPOSIX} inline; {$endif}
  31.     /// 在检查终止标志和此事件的同时,分步骤调用SleepHiRes()
  32.     function SleepStep(var start: Int64; terminated: PBoolean): Int64;
  33.     /// 如果使用了eventfd() API,则可用于调整算法
  34.     function IsEventFD: boolean;
  35.       {$ifdef HASINLINE} inline; {$endif}
  36. end;
复制代码
NewSynLocker
  1. /// 从堆初始化一个TSynLocker实例
  2. // - 调用DoneandFreeMem来释放相关内存和操作系统互斥锁
  3. // - 例如,在TSynPersistentLock中使用以减少类实例大小
  4. function NewSynLocker: PSynLocker;
复制代码
TSynLocked
  1. type
  2.   {$M+} // 开启内存管理消息
  3.   /// TSynPersistentLock的一个持久性无关替代方案
  4.   // - 当不需要自定义JSON持久性时,可以用作基类
  5.   // - 可以考虑将TRWLock字段用作更轻量级的多读/独占写选项
  6.   TSynLocked = class
  7.   protected
  8.     fSafe: PSynLocker; // TSynLocker会增加继承字段的偏移量
  9.   public
  10.     /// 初始化实例及其关联的锁
  11.     // - 定义为virtual,就像TObjectWithCustomCreate/TSynPersistent一样
  12.     constructor Create; virtual;
  13.     /// 终结实例及其关联的锁
  14.     destructor Destroy; override;
  15.     /// 访问关联的实例临界区
  16.     // - 调用Safe.Lock/UnLock来保护此存储的多线程访问
  17.     property Safe: PSynLocker
  18.       read fSafe;
  19.   end;
  20.   {$M-} // 关闭内存管理消息
  21.   /// TSynLocked层次的元类定义
  22.   TSynLockedClass = class of TSynLocked;
复制代码
TLecuyerThreadSafe
  1.   /// 线程安全的Pierre L'Ecuyer软件随机数生成器
  2.   // - 仅用TLightLock包装TLecuyer
  3.   // - 除非可能比threadvar稍快,否则不应使用
  4.   {$ifdef USERECORDWITHMETHODS}
  5.   TLecuyerThreadSafe = record
  6.   {$else}
  7.   TLecuyerThreadSafe = object
  8.   {$endif USERECORDWITHMETHODS}
  9.   public
  10.     Safe: TLightLock;
  11.     Generator: TLecuyer;
  12.     /// 计算下一个生成的32位值
  13.     function Next: cardinal; overload;
  14.     /// 计算一个64位浮点数
  15.     function NextDouble: double;
  16.     /// 用随机字节异或某个内存缓冲区
  17.     procedure Fill(dest: pointer; count: integer);
  18.     /// 用7位ASCII随机文本填充某个string[31]
  19.     procedure FillShort31(var dest: TShort31);
  20.   end;
  21.   TThreadIDDynArray = array of TThreadID; // 线程ID动态数组类型
  22. var
  23.   /// 全局线程安全的Pierre L'Ecuyer软件随机数生成器
  24.   // - 除非可能比threadvar稍快,否则不应使用
  25.   SharedRandom: TLecuyerThreadSafe;
复制代码
与线程、CPU核心和事件相干的类型和函数

[code]{$ifdef OSPOSIX}  /// 可设置为TRUE,以欺压SleepHiRes(0)调用POSIX sched_yield  // - 在实践中,据报道在POSIX体系上存在题目  // - 即使是Linus Torvalds本人也对它的利用表示愤怒 - 例如,请参见  // https://www.realworldtech.com/forum/?threadid=189711&curpostid=189752  // - 您可以自己尝试它  SleepHiRes0Yield: boolean = false;{$endif OSPOSIX}/// 类似于Windows的sleep() API调用,真正实现跨平台// - 利用毫秒级分辨率// - SleepHiRes(0)在Windows上调用ThreadSwitch,但在POSIX版本中将等待10微秒// 除非欺压SleepHiRes0Yield为true(坏主意)// - 相对于RTL的Sleep()函数,如果在任何OS信号中断时返回ESysEINTR// - 警告:通常在Windows上等待下一个体系计时器中断,默认为每16毫秒一次;// 因此,永远不要依赖提供的毫秒值来猜测经过的时间,而应调用GetTickCount64procedure SleepHiRes(ms: cardinal); overload;/// 类似于Windows的sleep() API调用,但真正实现跨平台// 并在等待期间检查Terminated标志以快速响应中断// - 如果terminated^被设置为true(terminatedvalue),则返回truefunction SleepHiRes(ms: cardinal; var terminated: boolean;  terminatedvalue: boolean = true): boolean; overload;/// 调用SleepHiRes(),思量活动的步长,在0/1/5/50/120-250毫秒步长中// - 范围设计激进,以响应性为代价燃烧一些CPU// - 当发生某些活动时,应重置start := 0,或在Windows上设置start := -1// 以避免任何SleepHiRes(0) = SwitchToThread调用// - 可选地在terminated^被设置或事件被信号触发时返回// - 返回当前的GetTickCount64值function SleepStep(var start: Int64; terminated: PBoolean = nil): Int64;/// 计算最佳就寝时间作为0/1/5/50然后120-250毫秒步长// - 范围设计激进,以响应性为代价燃烧一些CPUfunction SleepDelay(elapsed: PtrInt): PtrInt;/// 计算最佳就寝时间,类似于SleepStep,在0/1/5/50/120-250毫秒步长中// - 范围设计激进,以响应性为代价燃烧一些CPU// - start=0将用tix填充其值,start
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

冬雨财经

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表