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;
根據上述類定義編寫的 TBlockingProcess
和 TBlockingProcessPool
的例程程式碼。請注意,由於這些類可能依賴於特定的庫(如mORMot),以下示例將盡量保持通用性,並假設您已經有一個適當的環境來執行這些程式碼。
TBlockingProcess 例程程式碼
uses
SysUtils, Classes, // 引入SysUtils和Classes單元以使用WriteLn和TSynLocker等
// 假設YourSynapseUnit包含了TSynLocker和TBlockingProcess的定義
mormot.core.os,
mormot.core.thread;
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
。這通常透過傳遞池例項的引用或將其儲存在可從回撥訪問的全域性/靜態變數中來實現。