TPdfCancellationReason = (pcrNone, pcrUser, pcrTimeout, pcrLinked,
pcrShutdown, pcrSuperseded, pcrOther);
IPdfCancellationTokenEx = interface(IPdfCancellationToken)
function RegisterCallbackManaged(const ACallback: TThreadMethod): IPdfCancellationRegistration;
function WaitForCancellation(ATimeoutMs: Cardinal): Boolean;
property Reason: TPdfCancellationReason read GetReason;
property CancellationMessage: string read GetCancellationMessage;
property CancelledAtTick: UInt64 read GetCancelledAtTick;
property CallbackCount: Integer read GetCallbackCount;
property HasCallbacks: Boolean read GetHasCallbacks;
end;
IPdfCancellationTokenSourceEx = interface(IPdfCancellationTokenSource)
function TryCancel: Boolean;
function CancelWithReason(AReason: TPdfCancellationReason; const AMessage: string): Boolean;
property TokenEx: IPdfCancellationTokenEx read GetTokenEx;
end;
TPdfCancellationTokenSource = class
destructor Destroy; override;
class function New: IPdfCancellationTokenSource; static;
class function NewEx: IPdfCancellationTokenSourceEx; static;
class function NewTimeout(AMilliseconds: Cardinal; const AMessage: string = ''): IPdfCancellationTokenSourceEx; static;
end;
TPdfFutureOptions = record
DispatchMode: TPdfFutureDispatchMode;
ThreadPriority: TThreadPriority;
class function Default: TPdfFutureOptions; static;
end;
TPdfFuture<T> = class
class procedure Run(const AWorker: TPdfFutureWorker<T>; const AReply: TPdfFutureReply<T>; const AToken: IPdfCancellationToken = nil); static;
class procedure RunEx(const AWorker: TPdfFutureWorker<T>; const AReply: TPdfFutureReply<T>; const AToken: IPdfCancellationToken; const AOptions: TPdfFutureOptions); static;
end;
TPdfAsyncExecutor = class
constructor Create(AWorkerCount: Integer; AQueueCapacity: Integer = 0);
destructor Destroy; override;
function Submit(const AWorker: TPdfAsyncTaskWorker; const AReply: TPdfAsyncTaskReply = nil; APriority: TPdfAsyncPriority = papNormal; ADispatchMode: TPdfAsyncDispatchMode = padWorkerThread): IPdfAsyncTask;
function TrySubmit(const AWorker: TPdfAsyncTaskWorker; const AReply: TPdfAsyncTaskReply; out ATask: IPdfAsyncTask; APriority: TPdfAsyncPriority = papNormal; ADispatchMode: TPdfAsyncDispatchMode = padWorkerThread): Boolean;
function WaitForIdle(ATimeoutMs: Cardinal): Boolean;
function GetStats: TPdfAsyncExecutorStats;
procedure Shutdown(ACancelPending: Boolean = True);
property WorkerCount: Integer read FWorkerCount;
property QueueCapacity: Integer read FQueueCapacity;
property IsShutdown: Boolean read GetIsShutdown;
end;
TPdfAsyncExecutorStats = record
WorkerCount: Integer;
QueueCapacity: Integer;
QueuedCount: Integer;
RunningCount: Integer;
PeakQueuedCount: Integer;
SubmittedCount: Int64;
SucceededCount: Int64;
CancelledCount: Int64;
FailedCount: Int64;
RejectedCount: Int64;
end;
IPdfAsyncTask = interface
function Cancel: Boolean;
function WaitFor(ATimeoutMs: Cardinal): Boolean;
function Snapshot: TPdfAsyncTaskResult;
property Id: Int64 read GetId;
property State: TPdfAsyncTaskState read GetState;
property Priority: TPdfAsyncPriority read GetPriority;
property Token: IPdfCancellationToken read GetToken;
property IsCompleted: Boolean read GetIsCompleted;
end;
| 類型 | 說明 |
|---|---|
TPdfCancellationReason | 結構化的終止原因,涵蓋使用者要求、逾時、連結工作、關機、被取代的工作與應用程式自訂的取消 |
EPdfOperationCancelled | 取消例外,保留原始 Reason 與訊息以供診斷 |
IPdfCancellationToken | 相容的工作端權杖,支援 IsCancelled 輪詢、RegisterCallback、ThrowIfCancelled 與例外 |
IPdfCancellationTokenSource | 相容的擁有者端來源,含 Token 與等冪的 Cancel |
IPdfCancellationRegistration | 穩定的回呼註冊,含 Id、IsRegistered 與執行緒安全的 Unregister |
IPdfCancellationTokenEx | 擴充權杖,具取消中繼資料、回呼計數、可移除的回呼註冊,以及以事件為基礎的等待 |
IPdfCancellationTokenSourceEx | 擴充擁有者來源,具原子性 TryCancel、CancelWithReason 與強型別 TokenEx |
TPdfCancellationTokenSource | 執行緒安全的來源實作,透過 New、NewEx 或 NewTimeout 建立 |
PdfNoCancellationToken | 永不取消的共用權杖,避免為不可取消的工作配置來源 |
| 類型 | 說明 |
|---|---|
TPdfFutureStatus | 結果狀態:pfsSuccess、pfsCancelled 或 pfsFailure |
TPdfFutureDispatchMode | 回覆政策:pfdSynchronize 將回覆遞交至主執行緒,pfdWorkerThread 在工作者上叫用,pfdNone 則抑制回覆 |
TPdfFutureOptions | RunEx 的回覆分派與工作者 ThreadPriority 設定 |
TPdfFutureResult<T> | 完成封套,含 Value 與 HasValue、Status、ErrorMessage 與 ErrorClassName 配對、CancellationReason、OperationId、StartedAtTick 與 CompletedAtTick、狀態輔助成員,以及 ElapsedMilliseconds |
TPdfFutureWorker<T> | 方法指標型工作者,接收取消權杖並傳回背景結果 |
TPdfFutureReply<T> | 方法指標型回呼,接收完成的 TPdfFutureResult<T> |
TPdfFutureThread<T> | TPdfFuture<T> 使用的編譯器支援執行緒型別;透過 Create 或支援選項的 CreateEx 建構,應用程式通常呼叫 Run 或 RunEx |
TPdfFuture<T> | 射後不理的輔助型別,透過 Run 保留原有的同步回覆行為,並透過 RunEx 加入可設定的分派 |
| 類型 | 說明 |
|---|---|
TPdfAsyncPriority | 四條出列通道,從 papLow 到 papCritical,每條通道內部依 FIFO 順序 |
TPdfAsyncTaskState | 工作生命週期:patsQueued、patsRunning、patsSucceeded、patsCancelled 或 patsFailed |
TPdfAsyncDispatchMode | 回覆分派方式:padWorkerThread、padSynchronize,或以 padNone 抑制回覆 |
TPdfAsyncTaskWorker | 方法指標型工作項目,接收所屬工作的取消權杖 |
TPdfAsyncTaskReply | 方法指標型完成回呼,接收不可變的工作結果快照 |
TPdfAsyncTaskResult | TaskId、State、Priority、QueuedAtTick、StartedAtTick 與 CompletedAtTick 時序、ErrorMessage 與 ErrorClassName 工作者錯誤配對、連同訊息的 CancellationReason,以及隔離的 ReplyErrorMessage |
IPdfAsyncTask | 已提交工作的控制代碼,含 Cancel、支援逾時的 WaitFor、原子性 Snapshot,以及 Id、State、Priority、Token 與 IsCompleted 屬性 |
TPdfAsyncExecutorStats | 容量、目前負載、佇列深度峰值,以及累計的已提交、成功、取消、失敗與拒絕計數 |
EPdfAsyncQueueFull | 當有界佇列無法再接受工作時由 Submit 引發 |
EPdfAsyncExecutorShutdown | 在執行器開始關閉後由 Submit 引發 |
TPdfAsyncExecutor | 可重複使用的固定工作者集區,具備有界佇列、四個 O(1) 優先權環、合作式工作取消、統計資訊與平滑關機 |
| 函式 | 說明 |
|---|---|
PdfAsyncTick | 傳回 future 與執行器中繼資料所使用的單調毫秒刻度 |
PdfAsyncTickDelta | 計算防禦性的經過毫秒數,遺失或逆轉的刻度會傳回零 |
PdfNextAsyncId | 傳回處理序本機的正整數 ID,由 future、回呼註冊與執行器工作共用 |
var
CancelSource: IPdfCancellationTokenSourceEx;
begin
CancelSource := TPdfCancellationTokenSource.NewTimeout(5000, 'Export deadline exceeded');
TPdfFuture<Integer>.Run(Worker, Completed, CancelSource.TokenEx);
if UserRequestedCancel then
CancelSource.CancelWithReason(pcrUser, 'Export cancelled by user');
end;
var
Executor: TPdfAsyncExecutor;
Task: IPdfAsyncTask;
begin
Executor := TPdfAsyncExecutor.Create(4, 128);
try
if not Executor.TrySubmit(RenderPage, PageCompleted, Task, papHigh, padSynchronize) then
HandleBackpressure;
Executor.WaitForIdle(30000);
finally
Executor.Free;
end;
end;
Delphi POSIX 建置保留 TThreadPriority 選項值 tpIdle、tpLowest、tpLower、tpNormal、tpHigher、tpHighest 與 tpTimeCritical,維持原始碼相容性,但平台 RTL 只支援預設排程路徑。tpNormal 使用該路徑;以其他執行緒優先權建立 Future,會在啟動 Worker 前拋出 ENotSupportedException
重複或突發性的工作請使用 TPdfAsyncExecutor,讓工作重用固定的一組執行緒,而不是每個操作都建立一條執行緒
正數的佇列容量提供確定性的背壓,零則表示佇列無上限;執行中的工作不佔用佇列槽位
優先權排程在通道之間是嚴格的,通道內部則為 FIFO,因此請將 papCritical 與 papHigh 保留給真正延遲敏感的工作
從主執行緒呼叫時,WaitForIdle 會處理同步回呼,讓 padSynchronize 回覆能夠完成而不發生關機死結
每個逾時來源在取消或到期之前都會持有一條輕量等待執行緒,因此需要建立大量短時限時,建議改用共用的應用程式計時器或期限排程器
PDFium 物件擁有權規則仍然適用:為每個並行工作者建立或隔離一個 TPdf 實體,並且不要並行修改或算繪同一個作用中文件實體
原有的 IPdfCancellationToken、IPdfCancellationTokenSource、TPdfCancellationTokenSource.New 與 TPdfFuture<T>.Run API 保持原始碼相容
只有當需要結構化診斷、可移除回呼、逾時等待或原子性取消擁有權時,才使用擴充介面
回呼仍使用方法指標而非匿名方法,因此相同的 API 可在 Delphi、C++Builder 與 Free Pascal 下編譯