PDFium Delphi Component Docs

FPdfAsync unit

Unit: FPdfAsync
Cancellation, future, and bounded worker-pool infrastructure for responsive PDF processing in VCL, LCL, FMX, and headless applications

Syntax

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;

Cancellation types

TypeDescription
TPdfCancellationReasonStructured terminal reason covering user requests, timeouts, linked work, shutdown, superseded work, and application-defined cancellation
EPdfOperationCancelledCancellation exception with the original Reason and message preserved for diagnostics
IPdfCancellationTokenCompatibility worker-side token with IsCancelled polling, RegisterCallback, ThrowIfCancelled, and exception support
IPdfCancellationTokenSourceCompatibility owner-side source with Token and idempotent Cancel
IPdfCancellationRegistrationStable callback registration with Id, IsRegistered, and thread-safe Unregister
IPdfCancellationTokenExExtended token with cancellation metadata, callback counts, removable callback registration, and event-backed waiting
IPdfCancellationTokenSourceExExtended owner source with atomic TryCancel, CancelWithReason, and strongly typed TokenEx
TPdfCancellationTokenSourceThread-safe source implementation created with New, NewEx, or NewTimeout
PdfNoCancellationTokenShared token that never cancels and avoids allocating a source for non-cancelable work

Future types

TypeDescription
TPdfFutureStatusResult state: pfsSuccess, pfsCancelled, or pfsFailure
TPdfFutureDispatchModeReply policy: pfdSynchronize posts the reply to the main thread, pfdWorkerThread invokes it on the worker, and pfdNone suppresses the reply
TPdfFutureOptionsRunEx settings for reply dispatch and worker ThreadPriority
TPdfFutureResult<T>Completion envelope with Value and HasValue, Status, the ErrorMessage and ErrorClassName pair, the CancellationReason, OperationId, StartedAtTick and CompletedAtTick, status helpers, and ElapsedMilliseconds
TPdfFutureWorker<T>Method-pointer worker that receives a cancellation token and returns the background result
TPdfFutureReply<T>Method-pointer callback that receives the completed TPdfFutureResult<T>
TPdfFutureThread<T>Compiler-support thread type used by TPdfFuture<T>; constructed through Create or the options-aware CreateEx, and applications normally call Run or RunEx
TPdfFuture<T>Fire-and-forget helper that preserves the original synchronized-reply behaviour through Run and adds configurable dispatch through RunEx

Executor types

TypeDescription
TPdfAsyncPriorityFour dequeue lanes from papLow through papCritical, with FIFO order inside each lane
TPdfAsyncTaskStateTask lifecycle: patsQueued, patsRunning, patsSucceeded, patsCancelled, or patsFailed
TPdfAsyncDispatchModeReply dispatch through padWorkerThread, padSynchronize, or padNone to suppress the reply
TPdfAsyncTaskWorkerMethod-pointer work item that receives its task cancellation token
TPdfAsyncTaskReplyMethod-pointer completion callback receiving an immutable task result snapshot
TPdfAsyncTaskResultTaskId, State, Priority, QueuedAtTick, StartedAtTick, and CompletedAtTick timing, the ErrorMessage and ErrorClassName worker error pair, the CancellationReason with its message, and the isolated ReplyErrorMessage
IPdfAsyncTaskSubmitted-task handle with Cancel, timeout-aware WaitFor, atomic Snapshot, and the Id, State, Priority, Token, and IsCompleted properties
TPdfAsyncExecutorStatsCapacity, current load, peak queue depth, and cumulative submitted, succeeded, cancelled, failed, and rejected counts
EPdfAsyncQueueFullRaised by Submit when a bounded queue cannot accept another task
EPdfAsyncExecutorShutdownRaised by Submit after executor shutdown starts
TPdfAsyncExecutorReusable fixed worker pool with a bounded queue, four O(1) priority rings, cooperative task cancellation, statistics, and graceful shutdown

Timing and identity helpers

FunctionDescription
PdfAsyncTickReturns the monotonic millisecond tick used by future and executor metadata
PdfAsyncTickDeltaComputes a defensive elapsed-millisecond value and returns zero for missing or reversed ticks
PdfNextAsyncIdReturns a process-local positive ID shared by futures, callback registrations, and executor tasks

Cancellation example

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;

Bounded executor example

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;

Performance and threading

Delphi POSIX builds retain the TThreadPriority option values tpIdle, tpLowest, tpLower, tpNormal, tpHigher, tpHighest, and tpTimeCritical for source compatibility, but the platform RTL supports the default scheduling path only. tpNormal uses that path; constructing a future with another thread priority raises ENotSupportedException before starting a worker

Use TPdfAsyncExecutor for repeated or bursty work so tasks reuse a fixed set of threads instead of creating one thread per operation

A positive queue capacity provides deterministic backpressure while zero keeps the queue unbounded; running tasks do not consume queue slots

Priority scheduling is strict between lanes and FIFO within a lane, so reserve papCritical and papHigh for genuinely latency-sensitive work

WaitForIdle processes synchronized callbacks when called from the main thread, allowing padSynchronize replies to finish without a shutdown deadlock

Each timeout source owns one lightweight waiting thread until cancellation or expiry, so a shared application timer or deadline scheduler is preferable when creating very large numbers of short-lived deadlines

PDFium object ownership rules still apply: create or isolate a TPdf instance per concurrent worker and do not mutate or render the same active document instance concurrently

Compatibility

The original IPdfCancellationToken, IPdfCancellationTokenSource, TPdfCancellationTokenSource.New, and TPdfFuture<T>.Run APIs remain source-compatible

Use the extended interfaces only when structured diagnostics, removable callbacks, timeout waiting, or atomic cancellation ownership is required

Callbacks remain method pointers rather than anonymous methods so the same API compiles with Delphi, C++Builder, and Free Pascal

See Also

TPdf.RenderPageProgressive, TPdfView.AsyncRendering