首页 > 其他分享 >mormot.core.threads--TBlockingProcess

mormot.core.threads--TBlockingProcess

时间:2024-07-08 19:42:04浏览次数:10  
标签:TBlockingProcess core 调用 -- WaitFor mormot Process NotifyFinished TBlockingProce

mormot.core.threads--TBlockingProcess

type
  /// TBlockingProcess 实例的当前状态
  TBlockingEvent = (
    evNone,       // 无状态
    evWaiting,    // 等待状态
    evTimeOut,    // 超时状态
    evRaised);    // 触发状态

  {$M+} // 开启内存管理消息,用于调试
  /// 用于等待某个进程完成的信号量
  // - 例如,在mormot.rest.server.pas中的TBlockingCallback使用
  // - 一旦创建,进程将通过WaitFor调用阻塞,当后台线程调用NotifyFinished时释放
  TBlockingProcess = class(TSynEvent)
  protected
    fTimeOutMs: integer;       // 超时毫秒数
    fEvent: TBlockingEvent;    // 当前事件状态
    fOwnedSafe: boolean;       // 是否拥有同步锁
    fSafe: PSynLocker;         // 同步锁指针
    procedure ResetInternal; virtual; // 重置关联参数(可重写)
  public
    /// 初始化信号量实例
    // - 指定阻塞执行应视为失败的超时毫秒数(如果设置为0,则使用默认值3000)
    // - 应提供一个关联的互斥锁
    constructor Create(aTimeOutMs: integer; aSafe: PSynLocker);
      reintroduce; overload; virtual;
    /// 初始化信号量实例
    // - 指定阻塞执行应视为失败的超时毫秒数(如果设置为0,则使用默认值3000)
    // - 将创建并拥有一个关联的互斥锁
    constructor Create(aTimeOutMs: integer); reintroduce; overload; virtual;
    /// 销毁实例
    destructor Destroy; override;
    /// 等待NotifyFinished()被调用或触发超时
    // - 返回进程的最终状态,即evRaised或evTimeOut
    function WaitFor: TBlockingEvent; reintroduce; overload; virtual;
    /// 等待NotifyFinished()被调用或指定超时时间后触发超时
    // - 返回进程的最终状态,即evRaised或evTimeOut
    function WaitFor(TimeOutMS: integer): TBlockingEvent; reintroduce; overload; virtual;
    /// 应在后台进程完成时调用
    // - 调用者随后将允许其WaitFor方法返回
    // - 如果成功(即状态不是evRaised或evTimeout),则返回TRUE
    // - 如果实例已被锁定(例如,从TBlockingProcessPool.FromCallLocked检索时),您可以设置alreadyLocked=TRUE
    function NotifyFinished(alreadyLocked: boolean = false): boolean; virtual;
    /// 重置内部事件状态为evNone的包装器
    // - 在WaitFor/NotifyFinished过程成功后,可用于重用相同的TBlockingProcess实例
    // - 如果成功(即状态不是evWaiting),则返回TRUE,并将当前状态设置为evNone,并将Call属性设置为0
    // - 如果有WaitFor当前正在进行,则返回FALSE
    function Reset: boolean; virtual;
    /// 围绕fSafe^.Lock的包装器
    procedure Lock;
    /// 围绕fSafe^.Unlock的包装器
    procedure Unlock;
  published
    /// 进程的当前状态
    // - 在WaitFor过程后,使用Reset方法来重用此实例
    property Event: TBlockingEvent
      read fEvent;
    /// 构造函数中定义的超时周期(毫秒)
    property TimeOutMs: integer
      read fTimeOutMS;
  end;
  {$M-} // 关闭内存管理消息

  /// 用于标识每个TBlockingProcessPool调用的类型
  // - 允许匹配给定的TBlockingProcessPoolItem信号量
  TBlockingProcessPoolCall = type integer;

  /// 在TBlockingProcessPool中使用的信号量
  // - 该信号量具有一个Call字段来标识每次执行
  TBlockingProcessPoolItem = class(TBlockingProcess)
  protected
    fCall: TBlockingProcessPoolCall; // 调用标识符
    procedure ResetInternal; override; // 重置内部状态
  published
    /// 当由TBlockingProcessPool拥有时的唯一标识符
    // - Reset会将此字段恢复为其默认值0
    property Call: TBlockingProcessPoolCall
      read fCall;
  end;

  /// TBlockingProcess的类引用类型(元类)
  TBlockingProcessPoolItemClass = class of TBlockingProcessPoolItem;

  /// 管理TBlockingProcessPoolItem实例的池
  // - 每个调用将通过唯一的TBlockingProcessPoolCall值进行标识
  // - 用于模拟例如从异步事件驱动DDD进程中的阻塞执行
  // - 它还允许重用TEvent系统资源
  TBlockingProcessPool = class(TSynPersistent)
  protected
    fClass: TBlockingProcessPoolItemClass; // 池项类
    fPool: TSynObjectListLightLocked;      // 池
    fCallCounter: TBlockingProcessPoolCall; // 设置TBlockingProcessPoolItem.Call
  public
    /// 初始化池,对于给定的实现类
    constructor Create(aClass: TBlockingProcessPoolItemClass = nil); reintroduce;
    /// 销毁池
    // - 还将强制所有挂起的WaitFor触发evTimeOut
    destructor Destroy; override;
    /// 从内部池中预订一个TBlockingProcess
    // - 出错时返回nil(例如,实例正在销毁)
    // - 或者返回与此调用相对应的阻塞进程实例;
    // 其Call属性将标识异步回调的调用,然后在WaitFor之后,应运行Reset方法来释放池的互斥锁
    function NewProcess(aTimeOutMs: integer): TBlockingProcessPoolItem; virtual;
    /// 从其调用标识符检索TBlockingProcess
    // - 可用于例如从异步进程的回调中
    // 设置继承自TBlockingProcess的一些附加参数,
    // 然后调用NotifyFinished来释放调用者的WaitFor
    // - 如果leavelocked为TRUE,则返回的实例将被锁定:调用者应在使用后执行result.Unlock或NotifyFinished(true)
    function FromCall(call: TBlockingProcessPoolCall;
      locked: boolean = false): TBlockingProcessPoolItem; virtual;
  end;

根据上述类定义编写的 TBlockingProcessTBlockingProcessPool的例程代码。请注意,由于这些类可能依赖于特定的库(如mORMot),以下示例将尽量保持通用性,并假设您已经有一个适当的环境来运行这些代码。

TBlockingProcess 例程代码

uses
  SysUtils, Classes, // 引入SysUtils和Classes单元以使用WriteLn和TSynLocker等
  // 假设YourSynapseUnit包含了TSynLocker和TBlockingProcess的定义
  YourSynapseUnit;

var
  Process: TBlockingProcess;
  EventState: TBlockingEvent;
  Safe: TSynLocker;

begin
  try
    // 创建一个同步锁
    Safe := TSynLocker.Create;
    try
      // 创建一个TBlockingProcess实例,超时设置为5000毫秒,并传递同步锁
      Process := TBlockingProcess.Create(5000, @Safe);
      try
        // 模拟异步操作,这里我们直接调用WaitFor来阻塞当前线程
        EventState := Process.WaitFor;
        case EventState of
          evNone: WriteLn('Process state is evNone (should not happen)');
          evWaiting: WriteLn('Process state is evWaiting (should not happen during WaitFor)');
          evTimeOut: WriteLn('Process timed out');
          evRaised: WriteLn('Process was notified successfully');
        end;

        // 在实际应用中,这里可能是另一个线程调用NotifyFinished来释放WaitFor
        // 但为了演示,我们直接调用NotifyFinished(尽管这在实际应用中可能是不必要的)
        if Process.NotifyFinished then
          WriteLn('NotifyFinished called successfully (for demonstration purposes only)');

        // 重置TBlockingProcess实例以供重用(如果需要的话)
        // 在这个例子中,我们不会重用它,但展示如何调用Reset
        if Process.Reset then
          WriteLn('Process reset successfully');

      finally
        // 销毁TBlockingProcess实例
        Process.Free;
      end;
    finally
      // 销毁同步锁
      Safe.Free;
    end;
  except
    on E: Exception do
      WriteLn('Error: ' + E.Message);
  end;
end.

注意:在上面的示例中,NotifyFinished的调用可能是不必要的,因为在实际应用中,它通常是由另一个线程在异步操作完成时调用的。此外,Reset的调用也取决于您是否需要重用 TBlockingProcess实例。

TBlockingProcessPool 例程代码

uses
  SysUtils, Classes, // 引入SysUtils和Classes单元
  // 假设YourSynapseUnit包含了TBlockingProcessPool及其相关类的定义
  YourSynapseUnit;

procedure SimulateAsyncCallback(Call: TBlockingProcessPoolCall);
var
  Process: TBlockingProcessPoolItem;
begin
  // 从池中检索与调用标识符匹配的TBlockingProcessPoolItem
  Process := TBlockingProcessPool(Owner).FromCall(Call, True); // 假设Owner是TBlockingProcessPool的引用
  try
    // 在这里模拟异步操作的完成
    // ...

    // 通知等待的进程,异步操作已完成
    Process.NotifyFinished(True); // 由于我们之前已经锁定了Process,所以这里传递True
  finally
    // 如果我们之前没有调用NotifyFinished(True),则需要在这里解锁
    // 但在这个例子中,我们调用了NotifyFinished(True),所以不需要再次解锁
    // Process.Unlock; // 这行是注释掉的,因为不需要在这里解锁
  end;
end;

var
  Pool: TBlockingProcessPool;
  Process: TBlockingProcessPoolItem;
  Call: TBlockingProcessPoolCall;

begin
  try
    // 创建一个TBlockingProcessPool实例
    Pool := TBlockingProcessPool.Create(TBlockingProcessPoolItem);
    try
      // 从池中预订一个新的TBlockingProcessPoolItem
      Process := Pool.NewProcess(5000);
      if Assigned(Process) then
      begin
        // 获取调用标识符(在这个例子中,我们可能不需要直接使用它,但它对于回调是必需的)
        Call := Process.Call;

        // 在这里,您可能会启动一个异步操作,并在其回调中调用SimulateAsyncCallback
        // 但为了演示,我们直接调用SimulateAsyncCallback(尽管这在实际应用中可能是不必要的)
        SimulateAsyncCallback(Call);

        // 注意:在实际应用中,您不会在这里立即调用SimulateAsyncCallback,
        // 因为异步操作将在另一个线程或事件处理器中完成。
        // 在这里,我们只是模拟了异步回调的行为。

        // 由于我们直接模拟了回调,因此不需要再次调用WaitFor。
        // 在实际应用中,您将在启动异步操作后调用Process.WaitFor来等待其完成。

        // 重置TBlockingProcessPoolItem以供重用(如果需要的话)
        // 注意:在大多数情况下,您可能不需要在池中重用项,因为池会管理它们。
        // 但如果您确实需要重置它(例如,在异常情况下),您应该小心处理锁定。
        // 在这个例子中,我们不会重置它,因为池会处理它。

      end;
    finally
      // 销毁TBlockingProcessPool实例
      // 注意:在销毁池时,所有挂起的WaitFor调用都将被强制超时。
      Pool.Free;
    end;
  except
    on E: Exception do
      WriteLn('Error: ' + E.Message);
  end;
end.

注意:在上面的 TBlockingProcessPool示例中,SimulateAsyncCallback过程模拟了异步操作的回调。然而,在实际应用中,回调将由异步操作本身(例如,在另一个线程或事件处理器中)触发,而不是由您直接调用。此外,请注意 Owner的假设,它在这个例子中并未定义,但在实际应用中,您可能需要以某种方式访问 TBlockingProcessPool的实例,以便从回调中检索 TBlockingProcessPoolItem。这通常通过传递池实例的引用或将其存储在可从回调访问的全局/静态变量中来实现。

标签:TBlockingProcess,core,调用,--,WaitFor,mormot,Process,NotifyFinished,TBlockingProce
From: https://www.cnblogs.com/hieroly/p/18289945

相关文章

  • 常见的概率分布
    1.离散型分布1.1两点分布(伯努利分布/贝努利分布/0-1分布)称随机变量\(X\)服从参数为\(p\)的伯努利分布,如果它分别以概率\(p\)和\(1-p\)取1和0为值。​\[P(X=k)=p^k(1-p)^{1-k},\quadk=0,1\\X\simB(1,p)\\E(X)=p\\D(X)=p(1-p)\]1.2二项分布n次独立的伯努利......
  • 工具安装
    虚拟机——VMware安装Vmware官方地址kali镜像kali镜像win10镜像(教育版)工具站卸载工具——geek安装文件检索工具——everythingeverything下载地址截图工具——snipastesnipaste下载地址解压缩工具——7.zip7.zip下载地址文本编辑器——notepad++notepad++下......
  • CSE 105 Summer Session
    CSE 105Summer Session 1 2024Homework 1Due date: Sunday July 7 at 11:59pmInstructionsOne member of the group should upload your group submission to Gradescope. During thesubmissionprocess,theywillbepromptedtoaddthenameso......
  • C++数据结构底层实现算法
    1.vector底层数据结构为数组,支持快速随机访问2.list底层数据结构为双向链表,支持快速增删3.deque底层数据结构为一个中央控制器和多个缓冲区,详细见STL源码剖析P146,支持首尾(中间不能)快速增删,也支持随机访问deque是一个双端队列(double-endedqueue),也是在堆中保存内容的.每个......
  • 路径规划算法(1)
    传统路径规划算法      1、BUG避障算法Bug算法大概是人们能想象到的最简单的避障算法。其基本思想是机器人在路途中,跟踪各障碍物的轮廓,从而绕开它。BUG算法十分简单,就像虫子在黑盒中的移动一样,这种规划没有全局路径规划,只有局部路径规划。根据规则的不同分为BUG0,BU......
  • 【算法篇】KMP算法,一种高效的字符串匹配算法
    我们今天了解一个字符串匹配算法-KMP算法,内容难度相对来说较高,建议先收藏再细品!!!KMP算法的基本概念KMP算法是一种高效的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。该算法的主要使用场景就是在字符串(也叫主......
  • 期末考试游记
    在一楼考,神志比较清晰。第一天社会(ZJ的政史地合称),看到前两面直接懵了,感觉题目比前几次难。做到后面就还好,政治地理大题照常写满。因为这边是不让开卷考的,所以题目没那么活,最多也就把一两个知识点写上去写满,所以还算轻松。结束之后判断题最后一题争议有些大,最后的情况是TF都给......
  • 如何安全隐藏IP地址,防止网络攻击?
    当您想在互联网上保持隐私或匿名时,您应该做的第一件事就是隐藏您的IP地址。您的IP地址很容易被追踪到您,并被用来了解您的位置。下面的文章将教您如何隐藏自己,不让任何试图跟踪您的活动的人发现。什么是IP地址?首先,让我们稍微讨论一下什么是IP地址。您需要知道的是,每......
  • 如何安全隐藏IP地址,防止网络攻击?
    当您想在互联网上保持隐私或匿名时,您应该做的第一件事就是隐藏您的IP地址。您的IP地址很容易被追踪到您,并被用来了解您的位置。下面的文章将教您如何隐藏自己,不让任何试图跟踪您的活动的人发现。什么是IP地址?首先,让我们稍微讨论一下什么是IP地址。您需要知道的是,每......
  • 什么是静态住宅代理?一文看懂它
    静态住宅代理(也称为ISP代理)是最流行的代理类型之一。它们也是隐藏身份和在线匿名的最佳方式之一。但是您需要了解它们什么?是什么让它们如此特别?为什么您要使用住宅代理而不是仅仅使用常规代理服务?如果你感兴趣,那么就看下去!什么是静态住宅代理?首先,我们来谈谈住宅代理。住宅......