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-cancellable 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 synchronised-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 retains the TThreadPriority values tpIdle, tpLowest, tpLower, tpNormal, tpHigher, tpHighest and tpTimeCritical for source compatibility, although the RTL supports only default scheduling. tpNormal selects that route; constructing a future with any other priority raises ENotSupportedException before a worker starts

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 whilst 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 synchronised 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