mormot.core.threads--TSynBackgroundTimer

打印 上一主题 下一主题

主题 900|帖子 900|积分 2700

mormot.core.threads--TSynBackgroundTimer
  1. type
  2.   // TSynBackgroundThreadProcess 类声明(稍后定义)
  3.   TSynBackgroundThreadProcess = class;
  4.   /// 由 TSynBackgroundThreadProcess 定期执行的事件回调
  5.   TOnSynBackgroundThreadProcess = procedure(Sender: TSynBackgroundThreadProcess) of object;
  6.   /// 能够以给定周期运行方法的 TThread 类
  7.   TSynBackgroundThreadProcess = class(TSynBackgroundThreadAbstract)
  8.   protected
  9.     fOnProcess: TOnSynBackgroundThreadProcess; // 定期执行的方法回调
  10.     fOnException: TNotifyEvent; // 当 OnProcess 引发异常时执行的事件回调
  11.     fOnProcessMS: cardinal; // 定期执行任务的时间间隔(毫秒)
  12.     fStats: TSynMonitor; // 处理统计信息
  13.     procedure ExecuteLoop; override; // 重写执行循环
  14.   public
  15.     /// 初始化线程以进行周期性任务处理
  16.     // - 当 ProcessEvent.SetEvent 被调用或自上次处理以来过去了 aOnProcessMS 毫秒时,将调用 aOnProcess
  17.     // - 如果 aOnProcessMS 为 0,则等待直到 ProcessEvent.SetEvent 被调用
  18.     // - 您可以定义一些回调来嵌套线程执行,例如,分配给 TRestServer.BeginCurrentThread/EndCurrentThread
  19.     constructor Create(const aThreadName: RawUtf8;
  20.       const aOnProcess: TOnSynBackgroundThreadProcess;
  21.       aOnProcessMS: cardinal; const aOnBeforeExecute: TOnNotifyThread = nil;
  22.       const aOnAfterExecute: TOnNotifyThread = nil;
  23.       aStats: TSynMonitorClass = nil;
  24.       CreateSuspended: boolean = false); reintroduce; virtual;
  25.     /// 终结线程并等待其结束
  26.     destructor Destroy; override;
  27.     /// 访问周期性任务的实现事件
  28.     property OnProcess: TOnSynBackgroundThreadProcess
  29.       read fOnProcess;
  30.     /// 当 OnProcess 引发异常时执行的事件回调
  31.     // - 提供的 Sender 参数是引发的异常实例
  32.     property OnException: TNotifyEvent
  33.       read fOnException write fOnException;
  34.   published
  35.     /// 访问周期性任务处理的延迟时间(毫秒)
  36.     property OnProcessMS: cardinal
  37.       read fOnProcessMS write fOnProcessMS;
  38.     /// 处理统计信息
  39.     // - 如果在类构造函数中 aStats 为 nil,则可能为 nil
  40.     property Stats: TSynMonitor
  41.       read fStats;
  42.   end;
  43.   // TSynBackgroundTimer 类声明(稍后定义)
  44.   TSynBackgroundTimer = class;
  45.   /// 由 TSynBackgroundThreadProcess 定期执行的事件回调(特定于 TSynBackgroundTimer)
  46.   // - 如果此任务 FIFO 中没有挂起的消息,则 Msg 为 ''
  47.   // - 对于此任务 FIFO 中的每个挂起消息,都会设置 Msg
  48.   // - 在 mORMot 1 中,有一个 TWaitEvent 参数,现在已被移除
  49.   TOnSynBackgroundTimerProcess = procedure(Sender: TSynBackgroundTimer;
  50.     const Msg: RawUtf8) of object;
  51.   /// TSynBackgroundTimer 内部注册列表使用的记录类型
  52.   TSynBackgroundTimerTask = record
  53.     OnProcess: TOnSynBackgroundTimerProcess; // 处理任务的回调过程
  54.     Secs: cardinal; // 任务执行的间隔时间(秒)
  55.     NextTix: Int64; // 下一次执行任务的时间戳
  56.     Msg: TRawUtf8DynArray; // 与此任务关联的待处理消息队列
  57.     MsgSafe: TLightLock; // 保护 Msg[] 列表的轻量级锁
  58.   end;
  59.   /// 存储 TSynBackgroundTimer 内部注册列表的动态数组类型
  60.   TSynBackgroundTimerTaskDynArray = array of TSynBackgroundTimerTask;
  61.   /// 能够在后台线程中以定期的速度运行一个或多个任务的线程类
  62.   // - 例如,通过继承自 TRestBackgroundTimer 的 TRest.TimerEnable/TimerDisable 方法使用
  63.   // - 每个进程可以有自己的文本消息 FIFO 队列
  64.   // - 如果您期望更新某些 GUI,则应该使用 TTimer 组件(例如,周期为 200ms),
  65.   // 因为 TSynBackgroundTimer 将使用它自己的独立线程
  66.   TSynBackgroundTimer = class(TSynBackgroundThreadProcess)
  67.   protected
  68.     fTask: TSynBackgroundTimerTaskDynArray; // 内部任务列表
  69.     fTasks: TDynArrayLocked; // 任务列表的封装和同步访问
  70.     fProcessing: boolean; // 标记当前是否有任务正在处理
  71.     fProcessingCounter: integer; // 处理中的任务计数器(可能是内部使用)
  72.     procedure EverySecond(Sender: TSynBackgroundThreadProcess); // 每秒执行一次的回调,用于处理任务
  73.     function Find(const aProcess: TMethod): PtrInt; // 查找已注册的任务(内部使用)
  74.     function Add(const aOnProcess: TOnSynBackgroundTimerProcess;
  75.       const aMsg: RawUtf8; aExecuteNow: boolean): boolean; // 添加任务到内部列表
  76.   public
  77.     /// 初始化线程以进行周期性任务处理
  78.     // - 您可以定义一些回调来嵌套线程执行,例如,
  79.     // 分配给 TRestServer.BeginCurrentThread/EndCurrentThread,如 TRestBackgroundTimer.Create 所做
  80.     constructor Create(const aThreadName: RawUtf8;
  81.       const aOnBeforeExecute: TOnNotifyThread = nil;
  82.       aOnAfterExecute: TOnNotifyThread = nil;
  83.       aStats: TSynMonitorClass = nil;
  84.       aLogClass: TSynLogClass = nil); reintroduce; virtual;
  85.     /// 销毁线程
  86.     destructor Destroy; override;
  87.     /// 为在固定秒数周期上运行的任务定义一个处理方法
  88.     // - 对于 mORMot 服务上的后台进程,请考虑使用 TRest 的
  89.     // TimerEnable/TimerDisable 方法及其关联的 BackgroundTimer 线程
  90.     procedure Enable(const aOnProcess: TOnSynBackgroundTimerProcess;
  91.       aOnProcessSecs: cardinal);
  92.     /// 取消定义在固定秒数周期上运行的任务
  93.     // - aOnProcess 应通过之前的 Enable() 方法调用进行注册
  94.     // - 成功时返回 true,如果提供的任务未注册则返回 false
  95.     // - 对于 mORMot 服务上的后台进程,请考虑使用 TRestServer 的
  96.     // TimerEnable/TimerDisable 方法及其 TSynBackgroundTimer 线程
  97.     function Disable(const aOnProcess: TOnSynBackgroundTimerProcess): boolean;
  98.     /// 在任务的下一次执行期间添加要处理的消息
  99.     // - 提供的消息将被添加到与 aOnProcess 关联的内部 FIFO 列表中,
  100.     // 然后作为 aMsg 参数传递给每次调用
  101.     // - 如果 aExecuteNow 为 true,则不会等待下一个 aOnProcessSecs 的发生
  102.     // - aOnProcess 应通过之前的 Enable() 方法调用进行注册
  103.     // - 成功时返回 true,如果提供的任务未注册则返回 false
  104.     function EnQueue(const aOnProcess: TOnSynBackgroundTimerProcess;
  105.       const aMsg: RawUtf8; aExecuteNow: boolean = false): boolean; overload;
  106.     /// 在任务的下一次执行期间添加要处理的消息(格式化版本)
  107.     // - ...(与上一个 EnQueue 重载类似,但允许格式化消息)
  108.     function EnQueue(const aOnProcess: TOnSynBackgroundTimerProcess;
  109.       const aMsgFmt: RawUtf8; const Args: array of const;
  110.       aExecuteNow: boolean = false): boolean; overload;
  111.     /// 从处理列表中删除消息
  112.     // - 提供的消息将在与 aOnProcess 关联的内部 FIFO 列表中进行搜索,
  113.     // 如果找到则从列表中删除
  114.     // - aOnProcess 应通过之前的 Enable() 方法调用进行注册
  115.     // - 成功时返回 true,如果提供的消息未注册则返回 false
  116.     function DeQueue(const aOnProcess: TOnSynBackgroundTimerProcess;
  117.       const aMsg: RawUtf8): boolean;
  118.     /// 不等待下一个 aOnProcessSecs 发生,立即执行任务
  119.     // - aOnProcess 应通过之前的 Enable() 方法调用进行注册
  120.     // - 成功时返回 true,如果提供的任务未注册则返回 false
  121.     function ExecuteNow(const aOnProcess: TOnSynBackgroundTimerProcess): boolean;
  122.     /// 不等待下一个 aOnProcessSecs 发生,仅执行一次任务
  123.     // - aOnProcess 不需要通过之前的 Enable() 方法调用进行注册
  124.     function ExecuteOnce(const aOnProcess: TOnSynBackgroundTimerProcess): boolean;
  125.     /// 等待直到没有后台任务正在处理
  126.     procedure WaitUntilNotProcessing(timeoutsecs: integer = 10);
  127.     /// 对内部任务列表的低级访问
  128.     property Task: TSynBackgroundTimerTaskDynArray read fTask;
  129.     /// 对内部任务列表封装和安全的低级访问
  130.     property Tasks: TDynArrayLocked read fTasks;
  131.     /// 返回当前是否有任务正在处理
  132.     property Processing: boolean read fProcessing;
  133.   end;
复制代码
以下是一个使用 TSynBackgroundTimer类的示例。在这个示例中,我们将创建一个 TSynBackgroundTimer实例,启用一个周期性任务,向该任务添加消息,并等待一段时间以观察其实行。请注意,由于 TSynBackgroundTimer是设计为在背景线程中运行的,因此我们需要确保主线程不会立刻退出,以便能够看到背景任务的效果。
  1. uses
  2.   SysUtils, // 包含WriteLn等标准输出函数
  3.   mormot.core.threads;
  4. // 定义一个处理定时任务的回调过程
  5. procedure MyTimerTask(Sender: TObject; const Msg: RawUtf8);
  6. begin
  7.   WriteLn('Timer task executed at ' + DateTimeToStr(Now) + '. Message: ' + Msg);
  8.   // 在这里执行定时任务的其他逻辑...
  9. end;
  10. var
  11.   Timer: TSynBackgroundTimer;
  12. begin
  13.   try
  14.     // 创建TSynBackgroundTimer实例
  15.     Timer := TSynBackgroundTimer.Create('MyBackgroundTimer');
  16.     try
  17.       // 启用一个周期性任务,每2秒执行一次
  18.       Timer.Enable(@MyTimerTask, 2);
  19.       // 向任务队列添加消息
  20.       Timer.EnQueue(@MyTimerTask, 'Hello from the background timer!');
  21.       // 假设我们想要等待一段时间来观察后台定时器的行为
  22.       // 注意:在实际应用中,您可能不需要这样做,因为主线程可能会执行其他任务
  23.       WriteLn('Waiting for 10 seconds...');
  24.       Sleep(10000); // 等待10秒
  25.       // 如果需要,可以禁用周期性任务(在这个示例中我们不会禁用它)
  26.       // Timer.Disable(@MyTimerTask);
  27.       // 注意:由于我们调用了Sleep,主线程被阻塞了,因此我们可以看到后台定时器的输出
  28.       // 在实际应用中,您可能不需要这样做,因为主线程可能会继续执行其他任务
  29.     finally
  30.       // 销毁TSynBackgroundTimer实例
  31.       // 注意:在实际应用中,您可能希望等待所有后台任务完成后再销毁定时器
  32.       // 但在这个简单示例中,我们立即销毁它
  33.       Timer.Free;
  34.       // 由于我们立即销毁了定时器,并且主线程继续执行(尽管在这个示例中被Sleep阻塞了),
  35.       // 因此后台线程可能在定时器被销毁后仍然尝试执行回调,这可能会导致访问违规。
  36.       // 在实际应用中,您应该确保在销毁定时器之前所有后台任务都已经完成。
  37.       // 一个简单的方法是调用Timer.WaitUntilNotProcessing,但这在这个示例中是不必要的,
  38.       // 因为我们立即销毁了定时器并且知道没有更多的任务会被添加。
  39.     end;
  40.   except
  41.     on E: Exception do
  42.       WriteLn('Error: ' + E.Message);
  43.   end;
  44.   // 注意:在实际应用中,主线程可能会继续执行其他任务,
  45.   // 而后台定时器将在其自己的线程中继续运行,直到被禁用或销毁。
  46.   // 在这个示例中,由于我们调用了Sleep并且立即销毁了定时器,
  47.   // 因此后台线程可能没有机会执行更多的回调。
  48.   WriteLn('Program ended.');
  49.   // 在实际应用中,您可能希望在这里添加更多的清理代码或继续执行其他任务。
  50. end.
复制代码
重要注意事项

  • 在上述示例中,我们调用了 Sleep(10000);来模拟主线程中的其他工作,以便我们可以看到背景定时器的行为。在现实应用中,您可能不需要这样做,由于主线程可能会实行其他有用的任务。
  • 我们立刻烧毁了 TSynBackgroundTimer实例,这在现实应用中可能不是最佳做法。在烧毁定时器之前,您应该确保全部背景任务都已经完成。一个更安全的方法是调用 Timer.WaitUntilNotProcessing(尽管在这个简单示例中它是不必要的)。但是,请注意,如果定时器被禁用或没有更多的任务被添加,那么调用 WaitUntilNotProcessing可能会立刻返回。
  • 由于我们调用了 Sleep而且立刻烧毁了定时器,因今背景线程可能没有机会实行更多的回调。在现实应用中,您应该确保在烧毁定时器之前给背景线程足够的时间来完成其工作。
  • 请确保将 'YourSynapseUnit'替换为包含 TSynBackgroundTimer界说的现实单元名称。
当然,以下是根据上述类界说编写的TSynBackgroundThreadProcess和TSynBackgroundTimer两个类的例程代码。请注意,由于这些类可能依靠于特定的库(如mORMot),以下示例将尽可能地保持通用性,并假设您已经有一个得当的环境来运行这些代码。
TSynBackgroundThreadProcess 例程代码
  1. uses
  2.   SysUtils, Classes, // 引入SysUtils和Classes单元以使用WriteLn和TThread等
  3.   // 假设YourSynapseUnit包含了TSynBackgroundThreadProcess的定义
  4.   YourSynapseUnit;
  5. procedure MyProcessMethod(Sender: TSynBackgroundThreadProcess);
  6. begin
  7.   WriteLn('Process method called in background thread.');
  8.   // 在这里执行您的后台处理逻辑
  9. end;
  10. var
  11.   BGThread: TSynBackgroundThreadProcess;
  12. begin
  13.   try
  14.     // 创建TSynBackgroundThreadProcess实例
  15.     BGThread := TSynBackgroundThreadProcess.Create(
  16.       'MyBackgroundThread', // 线程名称
  17.       MyProcessMethod, // 周期性执行的方法
  18.       1000, // 周期时间,单位为毫秒
  19.       nil, // OnBeforeExecute回调,这里不使用
  20.       nil  // OnAfterExecute回调,这里不使用
  21.       // aStats和其他参数根据需要进行设置
  22.     );
  23.     try
  24.       // 启动线程(注意:在TSynBackgroundThreadProcess的构造函数中,
  25.       // 如果CreateSuspended参数为false,则线程将自动启动)
  26.       // 在这个例子中,我们假设CreateSuspended默认为false
  27.       // 等待一段时间以观察后台线程的行为
  28.       // 注意:在实际应用中,您可能不需要这样做,因为主线程可能会继续执行其他任务
  29.       Sleep(5000); // 等待5秒
  30.     finally
  31.       // 销毁线程对象(注意:在析构函数中,线程将尝试优雅地终止)
  32.       BGThread.Free;
  33.       // 等待线程真正结束(可选,但在这个例子中我们依赖析构函数的行为)
  34.     end;
  35.   except
  36.     on E: Exception do
  37.       WriteLn('Error: ' + E.Message);
  38.   end;
  39.   WriteLn('Program ended.');
  40. end.
复制代码
注意:在上面的示例中,我假设TSynBackgroundThreadProcess的构造函数有一个CreateSuspended参数(这在尺度的TThread构造函数中是存在的),但根据您提供的类界说,这个参数现实上并没有在TSynBackgroundThreadProcess的构造函数中明确列出。如果TSynBackgroundThreadProcess是自动启动线程的,那么您可能不需要显式调用任何启动方法。
TSynBackgroundTimer 例程代码
  1. uses
  2.   SysUtils, // 引入SysUtils单元以使用WriteLn
  3.   // 假设YourSynapseUnit包含了TSynBackgroundTimer的定义
  4.   YourSynapseUnit;
  5. procedure MyTimerProcess(Sender: TSynBackgroundTimer; const Msg: RawUtf8);
  6. begin
  7.   WriteLn('Timer process called in background thread. Message: ' + Msg);
  8.   // 在这里执行您的定时任务逻辑
  9. end;
  10. var
  11.   Timer: TSynBackgroundTimer;
  12. begin
  13.   try
  14.     // 创建TSynBackgroundTimer实例
  15.     Timer := TSynBackgroundTimer.Create(
  16.       'MyBackgroundTimer' // 线程名称
  17.       // 其他参数根据需要进行设置,这里省略了OnBeforeExecute、OnAfterExecute、aStats和aLogClass
  18.     );
  19.     try
  20.       // 启用一个周期性任务,每2秒执行一次
  21.       Timer.Enable(@MyTimerProcess, 2);
  22.       // 向任务队列添加消息,并请求立即执行(尽管在这个上下文中,立即执行可能不会立即发生)
  23.       Timer.EnQueue(@MyTimerProcess, 'Hello from background timer!', true);
  24.       // 等待一段时间以观察后台定时器的行为
  25.       // 注意:在实际应用中,您可能不需要这样做,因为主线程可能会继续执行其他任务
  26.       Sleep(10000); // 等待10秒
  27.       // 禁用周期性任务(在这个示例中我们不会禁用它,但展示了如何禁用)
  28.       // Timer.Disable(@MyTimerProcess);
  29.     finally
  30.       // 销毁TSynBackgroundTimer实例(注意:在实际应用中,您可能希望等待所有后台任务完成后再销毁定时器)
  31.       // 但在这个简单示例中,我们立即销毁它
  32.       Timer.Free;
  33.       // 由于我们立即销毁了定时器,并且主线程继续执行(尽管在这个示例中被Sleep阻塞了),
  34.       // 因此后台线程可能没有机会执行更多的回调。
  35.       // 在实际应用中,您应该确保在销毁定时器之前给后台线程足够的时间来完成其工作。
  36.     end;
  37.   except
  38.     on E: Exception do
  39.       WriteLn('Error: ' + E.Message);
  40.   end;
  41.   WriteLn('Program ended.');
  42. end.
复制代码
在上面的TSynBackgroundTimer示例中,我展示了如何创建定时器、启用周期性任务、向任务队列添加消息,并等待一段时间以观察定时器的行为。请注意,由于我们调用了Sleep而且立刻烧毁了定时器,因今背景线程可能没有机会实行更多的回调。在现实应用中,您应该确保在烧毁定时器之前给背景线程足够的时间来完成其工作,或者调用Timer.WaitUntilNotProcessing(如果该类提供了这样的方法)来等待全部背景任务完成。然而,根据提供的类界说,TSynBackgroundTimer并没有直接提供WaitUntilNotProcessing方法,所以您可能需要实现本身的同步机制来达到这个目的。

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

使用道具 举报

0 个回复

倒序浏览

快速回复

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

本版积分规则

滴水恩情

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