mormot.core.threads--TSynThread

海利鸟發表於2024-07-09

mormot.core.threads--TSynThread

{ ************ 面向伺服器程序的執行緒池 }

type
  {$M+} // 開啟記憶體管理訊息,用於除錯

  /// 一個簡單的TThread,具有線上程上下文中執行的"Terminate"事件
  // - TThread.OnTerminate事件在Synchronize()內部執行,因此不符合我們的期望,
  // 即線上程建立的上下文中釋放資源(例如,對於COM物件或某些資料庫驅動程式)
  // - 由THttpServerGeneric.NotifyThreadStart()內部使用 - 您不應該使用受保護的fOnThreadTerminate事件處理程式
  // - 還定義了一個Start方法,以與Delphi的舊版本相容
  TSynThread = class(TThreadAbstract)
  protected
    fStartNotified: TObject; // 標記執行緒是否已通知開始
    // 我們定義了一個fOnThreadTerminate事件,該事件將在終止的執行緒上下文中執行
    // (而TThread.OnTerminate在主執行緒中呼叫)
    // -> 參見THttpServerGeneric.OnHttpThreadTerminate事件屬性
    fOnThreadTerminate: TOnNotifyThread;
    procedure DoTerminate; override; // 重寫DoTerminate方法
  public
    /// 初始化執行緒例項,處於非掛起狀態
    constructor Create(CreateSuspended: boolean); reintroduce; virtual;
    /// Sleep的安全版本,不會中斷執行緒程序
    // - 如果執行緒已終止,則返回TRUE
    // - 如果成功等待了MS毫秒,則返回FALSE
    function SleepOrTerminated(MS: cardinal): boolean;
    /// 確保僅在NotifyThreadStart完成後呼叫fOnThreadTerminate
    property StartNotified: TObject
      read fStartNotified write fStartNotified;
  end;

  /// 實現具有開始/停止通知功能的執行緒的抽象類
  // - 例如,伺服器執行緒
  // - 不要使用這個類,而是使用THttpServer, THttpApiServer或TWebSocketServer(如mormot.net.websock中定義的)
  TNotifiedThread = class(TSynThread)
  protected
    fProcessName: RawUtf8; // 程序名稱
    fOnThreadStart: TOnNotifyThread; // 執行緒開始通知事件
    procedure SetOnTerminate(const Event: TOnNotifyThread); virtual; // 設定執行緒終止事件
    procedure NotifyThreadStart(Sender: TSynThread); // 通知執行緒開始
  public
    /// 初始化伺服器例項,處於非掛起狀態
    constructor Create(CreateSuspended: boolean;
      const OnStart, OnStop: TOnNotifyThread; // 開始和停止通知事件
      const ProcessName: RawUtf8); reintroduce; virtual;
    /// 將每個執行緒分配給單個邏輯CPU核心
    // - 例如,對於HTTP伺服器,它可能確保具有短生命週期請求和高執行緒數的更好的可擴充套件性
    procedure SetServerThreadsAffinityPerCpu(
      const log: ISynLog; const threads: TThreadDynArray);
    /// 將每個執行緒分配給單個硬體CPU插槽
    // - 例如,對於具有多個物理CPU包的複雜硬體上的HTTP伺服器,它可能確保更好的可擴充套件性
    // - 但這非常挑剔,因此僅應在實際硬體上進行適當測試後才能啟用
    procedure SetServerThreadsAffinityPerSocket(
      const log: ISynLog; const threads: TThreadDynArray);
  end;

  /// 實現具有日誌通知功能的執行緒的抽象類
  TLoggedThread = class(TSynThread)
  protected
    fProcessName: RawUtf8; // 程序名稱
    fLogClass: TSynLogClass; // 日誌類
    fLog: TSynLog; // 在DoExecute執行緒上下文中的日誌例項
    fProcessing: boolean; // 標記執行緒是否正在處理
    procedure Execute; override; // 重寫Execute方法
    // 繼承類應該重寫此方法以實現適當的處理邏輯
    procedure DoExecute; virtual; abstract;
  public
    /// 初始化伺服器例項,處於非掛起狀態
    constructor Create(CreateSuspended: boolean; Logger: TSynLogClass;
      const ProcName: RawUtf8); reintroduce; virtual;
    /// 通知執行緒終止,並等待DoExecute完成
    procedure TerminateAndWaitFinished(TimeOutMs: integer = 5000); virtual;
    /// 關聯的日誌類
    property LogClass: TSynLogClass
      read fLogClass;
  published
    /// 此執行緒的名稱,作為SetCurrentThreadName()的引數提供
    property ProcessName: RawUtf8
      read fProcessName;
  end;

  /// 在後臺執行緒中由TLoggedWorkThread.Create呼叫的事件
  TOnLoggedWorkProcess = procedure(const Context: TDocVariantData) of object;

  /// 一個能夠在後臺執行緒中執行某些程序,並具有適當日誌記錄和最終通知功能的類
  TLoggedWorkThread = class(TLoggedThread)
  protected
    fSender: TObject; // 傳送者物件
    fOnExecute, fOnExecuted: TNotifyEvent; // 執行前後的事件
    fOnExecuteParam: TOnLoggedWorkProcess; // 執行引數的事件
    fContext: TDocVariantData; // 上下文資料
    procedure DoExecute; override; // 重寫DoExecute方法
  public
    /// 此建構函式將直接在後臺啟動執行緒
    // - 上下文作為常規的TNotifyEvent
    constructor Create(Logger: TSynLogClass; const ProcessName: RawUtf8;
      Sender: TObject; const OnExecute: TNotifyEvent;
      const OnExecuted: TNotifyEvent = nil);
        reintroduce; overload;
    /// 此建構函式將直接在後臺啟動執行緒
    // - 上下文作為具有名稱/值對的TDocVariantData物件
    constructor Create(Logger: TSynLogClass; const ProcessName: RawUtf8;
      const NameValuePairs: array of const; const OnExecute: TOnLoggedWorkProcess;
      const OnExecuted: TNotifyEvent = nil);
        reintroduce; overload;
  end;