mormot.core.threads--TBlockingProcess

打印 上一主题 下一主题

主题 930|帖子 930|积分 2790

mormot.core.threads--TBlockingProcess
  1. type
  2.   /// TBlockingProcess 实例的当前状态
  3.   TBlockingEvent = (
  4.     evNone,       // 无状态
  5.     evWaiting,    // 等待状态
  6.     evTimeOut,    // 超时状态
  7.     evRaised);    // 触发状态
  8.   {$M+} // 开启内存管理消息,用于调试
  9.   /// 用于等待某个进程完成的信号量
  10.   // - 例如,在mormot.rest.server.pas中的TBlockingCallback使用
  11.   // - 一旦创建,进程将通过WaitFor调用阻塞,当后台线程调用NotifyFinished时释放
  12.   TBlockingProcess = class(TSynEvent)
  13.   protected
  14.     fTimeOutMs: integer;       // 超时毫秒数
  15.     fEvent: TBlockingEvent;    // 当前事件状态
  16.     fOwnedSafe: boolean;       // 是否拥有同步锁
  17.     fSafe: PSynLocker;         // 同步锁指针
  18.     procedure ResetInternal; virtual; // 重置关联参数(可重写)
  19.   public
  20.     /// 初始化信号量实例
  21.     // - 指定阻塞执行应视为失败的超时毫秒数(如果设置为0,则使用默认值3000)
  22.     // - 应提供一个关联的互斥锁
  23.     constructor Create(aTimeOutMs: integer; aSafe: PSynLocker);
  24.       reintroduce; overload; virtual;
  25.     /// 初始化信号量实例
  26.     // - 指定阻塞执行应视为失败的超时毫秒数(如果设置为0,则使用默认值3000)
  27.     // - 将创建并拥有一个关联的互斥锁
  28.     constructor Create(aTimeOutMs: integer); reintroduce; overload; virtual;
  29.     /// 销毁实例
  30.     destructor Destroy; override;
  31.     /// 等待NotifyFinished()被调用或触发超时
  32.     // - 返回进程的最终状态,即evRaised或evTimeOut
  33.     function WaitFor: TBlockingEvent; reintroduce; overload; virtual;
  34.     /// 等待NotifyFinished()被调用或指定超时时间后触发超时
  35.     // - 返回进程的最终状态,即evRaised或evTimeOut
  36.     function WaitFor(TimeOutMS: integer): TBlockingEvent; reintroduce; overload; virtual;
  37.     /// 应在后台进程完成时调用
  38.     // - 调用者随后将允许其WaitFor方法返回
  39.     // - 如果成功(即状态不是evRaised或evTimeout),则返回TRUE
  40.     // - 如果实例已被锁定(例如,从TBlockingProcessPool.FromCallLocked检索时),您可以设置alreadyLocked=TRUE
  41.     function NotifyFinished(alreadyLocked: boolean = false): boolean; virtual;
  42.     /// 重置内部事件状态为evNone的包装器
  43.     // - 在WaitFor/NotifyFinished过程成功后,可用于重用相同的TBlockingProcess实例
  44.     // - 如果成功(即状态不是evWaiting),则返回TRUE,并将当前状态设置为evNone,并将Call属性设置为0
  45.     // - 如果有WaitFor当前正在进行,则返回FALSE
  46.     function Reset: boolean; virtual;
  47.     /// 围绕fSafe^.Lock的包装器
  48.     procedure Lock;
  49.     /// 围绕fSafe^.Unlock的包装器
  50.     procedure Unlock;
  51.   published
  52.     /// 进程的当前状态
  53.     // - 在WaitFor过程后,使用Reset方法来重用此实例
  54.     property Event: TBlockingEvent
  55.       read fEvent;
  56.     /// 构造函数中定义的超时周期(毫秒)
  57.     property TimeOutMs: integer
  58.       read fTimeOutMS;
  59.   end;
  60.   {$M-} // 关闭内存管理消息
  61.   /// 用于标识每个TBlockingProcessPool调用的类型
  62.   // - 允许匹配给定的TBlockingProcessPoolItem信号量
  63.   TBlockingProcessPoolCall = type integer;
  64.   /// 在TBlockingProcessPool中使用的信号量
  65.   // - 该信号量具有一个Call字段来标识每次执行
  66.   TBlockingProcessPoolItem = class(TBlockingProcess)
  67.   protected
  68.     fCall: TBlockingProcessPoolCall; // 调用标识符
  69.     procedure ResetInternal; override; // 重置内部状态
  70.   published
  71.     /// 当由TBlockingProcessPool拥有时的唯一标识符
  72.     // - Reset会将此字段恢复为其默认值0
  73.     property Call: TBlockingProcessPoolCall
  74.       read fCall;
  75.   end;
  76.   /// TBlockingProcess的类引用类型(元类)
  77.   TBlockingProcessPoolItemClass = class of TBlockingProcessPoolItem;
  78.   /// 管理TBlockingProcessPoolItem实例的池
  79.   // - 每个调用将通过唯一的TBlockingProcessPoolCall值进行标识
  80.   // - 用于模拟例如从异步事件驱动DDD进程中的阻塞执行
  81.   // - 它还允许重用TEvent系统资源
  82.   TBlockingProcessPool = class(TSynPersistent)
  83.   protected
  84.     fClass: TBlockingProcessPoolItemClass; // 池项类
  85.     fPool: TSynObjectListLightLocked;      // 池
  86.     fCallCounter: TBlockingProcessPoolCall; // 设置TBlockingProcessPoolItem.Call
  87.   public
  88.     /// 初始化池,对于给定的实现类
  89.     constructor Create(aClass: TBlockingProcessPoolItemClass = nil); reintroduce;
  90.     /// 销毁池
  91.     // - 还将强制所有挂起的WaitFor触发evTimeOut
  92.     destructor Destroy; override;
  93.     /// 从内部池中预订一个TBlockingProcess
  94.     // - 出错时返回nil(例如,实例正在销毁)
  95.     // - 或者返回与此调用相对应的阻塞进程实例;
  96.     // 其Call属性将标识异步回调的调用,然后在WaitFor之后,应运行Reset方法来释放池的互斥锁
  97.     function NewProcess(aTimeOutMs: integer): TBlockingProcessPoolItem; virtual;
  98.     /// 从其调用标识符检索TBlockingProcess
  99.     // - 可用于例如从异步进程的回调中
  100.     // 设置继承自TBlockingProcess的一些附加参数,
  101.     // 然后调用NotifyFinished来释放调用者的WaitFor
  102.     // - 如果leavelocked为TRUE,则返回的实例将被锁定:调用者应在使用后执行result.Unlock或NotifyFinished(true)
  103.     function FromCall(call: TBlockingProcessPoolCall;
  104.       locked: boolean = false): TBlockingProcessPoolItem; virtual;
  105.   end;
复制代码
根据上述类定义编写的 TBlockingProcess和 TBlockingProcessPool的例程代码。请留意,由于这些类可能依靠于特定的库(如mORMot),以下示例将尽量保持通用性,并假设您已经有一个适当的环境来运行这些代码。
TBlockingProcess 例程代码
  1. uses
  2.   SysUtils, Classes, // 引入SysUtils和Classes单元以使用WriteLn和TSynLocker等
  3.   // 假设YourSynapseUnit包含了TSynLocker和TBlockingProcess的定义
  4.   YourSynapseUnit;
  5. var
  6.   Process: TBlockingProcess;
  7.   EventState: TBlockingEvent;
  8.   Safe: TSynLocker;
  9. begin
  10.   try
  11.     // 创建一个同步锁
  12.     Safe := TSynLocker.Create;
  13.     try
  14.       // 创建一个TBlockingProcess实例,超时设置为5000毫秒,并传递同步锁
  15.       Process := TBlockingProcess.Create(5000, @Safe);
  16.       try
  17.         // 模拟异步操作,这里我们直接调用WaitFor来阻塞当前线程
  18.         EventState := Process.WaitFor;
  19.         case EventState of
  20.           evNone: WriteLn('Process state is evNone (should not happen)');
  21.           evWaiting: WriteLn('Process state is evWaiting (should not happen during WaitFor)');
  22.           evTimeOut: WriteLn('Process timed out');
  23.           evRaised: WriteLn('Process was notified successfully');
  24.         end;
  25.         // 在实际应用中,这里可能是另一个线程调用NotifyFinished来释放WaitFor
  26.         // 但为了演示,我们直接调用NotifyFinished(尽管这在实际应用中可能是不必要的)
  27.         if Process.NotifyFinished then
  28.           WriteLn('NotifyFinished called successfully (for demonstration purposes only)');
  29.         // 重置TBlockingProcess实例以供重用(如果需要的话)
  30.         // 在这个例子中,我们不会重用它,但展示如何调用Reset
  31.         if Process.Reset then
  32.           WriteLn('Process reset successfully');
  33.       finally
  34.         // 销毁TBlockingProcess实例
  35.         Process.Free;
  36.       end;
  37.     finally
  38.       // 销毁同步锁
  39.       Safe.Free;
  40.     end;
  41.   except
  42.     on E: Exception do
  43.       WriteLn('Error: ' + E.Message);
  44.   end;
  45. end.
复制代码
留意:在上面的示例中,NotifyFinished的调用可能是不必要的,由于在实际应用中,它通常是由另一个线程在异步操作完成时调用的。此外,Reset的调用也取决于您是否需要重用 TBlockingProcess实例。
TBlockingProcessPool 例程代码
  1. uses
  2.   SysUtils, Classes, // 引入SysUtils和Classes单元
  3.   // 假设YourSynapseUnit包含了TBlockingProcessPool及其相关类的定义
  4.   YourSynapseUnit;
  5. procedure SimulateAsyncCallback(Call: TBlockingProcessPoolCall);
  6. var
  7.   Process: TBlockingProcessPoolItem;
  8. begin
  9.   // 从池中检索与调用标识符匹配的TBlockingProcessPoolItem
  10.   Process := TBlockingProcessPool(Owner).FromCall(Call, True); // 假设Owner是TBlockingProcessPool的引用
  11.   try
  12.     // 在这里模拟异步操作的完成
  13.     // ...
  14.     // 通知等待的进程,异步操作已完成
  15.     Process.NotifyFinished(True); // 由于我们之前已经锁定了Process,所以这里传递True
  16.   finally
  17.     // 如果我们之前没有调用NotifyFinished(True),则需要在这里解锁
  18.     // 但在这个例子中,我们调用了NotifyFinished(True),所以不需要再次解锁
  19.     // Process.Unlock; // 这行是注释掉的,因为不需要在这里解锁
  20.   end;
  21. end;
  22. var
  23.   Pool: TBlockingProcessPool;
  24.   Process: TBlockingProcessPoolItem;
  25.   Call: TBlockingProcessPoolCall;
  26. begin
  27.   try
  28.     // 创建一个TBlockingProcessPool实例
  29.     Pool := TBlockingProcessPool.Create(TBlockingProcessPoolItem);
  30.     try
  31.       // 从池中预订一个新的TBlockingProcessPoolItem
  32.       Process := Pool.NewProcess(5000);
  33.       if Assigned(Process) then
  34.       begin
  35.         // 获取调用标识符(在这个例子中,我们可能不需要直接使用它,但它对于回调是必需的)
  36.         Call := Process.Call;
  37.         // 在这里,您可能会启动一个异步操作,并在其回调中调用SimulateAsyncCallback
  38.         // 但为了演示,我们直接调用SimulateAsyncCallback(尽管这在实际应用中可能是不必要的)
  39.         SimulateAsyncCallback(Call);
  40.         // 注意:在实际应用中,您不会在这里立即调用SimulateAsyncCallback,
  41.         // 因为异步操作将在另一个线程或事件处理器中完成。
  42.         // 在这里,我们只是模拟了异步回调的行为。
  43.         // 由于我们直接模拟了回调,因此不需要再次调用WaitFor。
  44.         // 在实际应用中,您将在启动异步操作后调用Process.WaitFor来等待其完成。
  45.         // 重置TBlockingProcessPoolItem以供重用(如果需要的话)
  46.         // 注意:在大多数情况下,您可能不需要在池中重用项,因为池会管理它们。
  47.         // 但如果您确实需要重置它(例如,在异常情况下),您应该小心处理锁定。
  48.         // 在这个例子中,我们不会重置它,因为池会处理它。
  49.       end;
  50.     finally
  51.       // 销毁TBlockingProcessPool实例
  52.       // 注意:在销毁池时,所有挂起的WaitFor调用都将被强制超时。
  53.       Pool.Free;
  54.     end;
  55.   except
  56.     on E: Exception do
  57.       WriteLn('Error: ' + E.Message);
  58.   end;
  59. end.
复制代码
留意:在上面的 TBlockingProcessPool示例中,SimulateAsyncCallback过程模拟了异步操作的回调。然而,在实际应用中,回调将由异步操作本身(例如,在另一个线程或事件处置处罚器中)触发,而不是由您直接调用。此外,请留意 Owner的假设,它在这个例子中并未定义,但在实际应用中,您可能需要以某种方式访问 TBlockingProcessPool的实例,以便从回调中检索 TBlockingProcessPoolItem。这通常通过传递池实例的引用或将其存储在可从回调访问的全局/静态变量中来实现。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

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

本版积分规则

汕尾海湾

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