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;
| Type | Description |
|---|---|
TPdfCancellationReason | Структурированная причина завершения, охватывающая запросы пользователя, таймауты, связанную работу, остановку приложения, устаревшую работу и определяемую приложением отмену |
EPdfOperationCancelled | Исключение отмены с сохранёнными для диагностики исходными Reason и сообщением |
IPdfCancellationToken | Совместимый токен рабочей стороны с опросом IsCancelled, RegisterCallback, ThrowIfCancelled и поддержкой исключений |
IPdfCancellationTokenSource | Совместимый источник стороны владельца со свойством Token и идемпотентным Cancel |
IPdfCancellationRegistration | Стабильная регистрация обратного вызова с Id, IsRegistered и потокобезопасным Unregister |
IPdfCancellationTokenEx | Расширенный токен с метаданными отмены, счётчиками обратных вызовов, съёмной регистрацией обратных вызовов и ожиданием на событиях |
IPdfCancellationTokenSourceEx | Расширенный источник владельца с атомарными TryCancel и CancelWithReason и строго типизированным TokenEx |
TPdfCancellationTokenSource | Потокобезопасная реализация источника, создаваемая через New, NewEx или NewTimeout |
PdfNoCancellationToken | Общий токен, который никогда не отменяется и избавляет от выделения источника для неотменяемой работы |
| Type | Description |
|---|---|
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> | Помощник fire-and-forget, сохраняющий исходное поведение синхронизированного ответа через Run и добавляющий настраиваемую диспетчеризацию через RunEx |
| Type | Description |
|---|---|
TPdfAsyncPriority | Четыре очереди извлечения от papLow до papCritical с порядком FIFO внутри каждой |
TPdfAsyncTaskState | Жизненный цикл задачи: patsQueued, patsRunning, patsSucceeded, patsCancelled или patsFailed |
TPdfAsyncDispatchMode | Диспетчеризация ответа через padWorkerThread, padSynchronize или подавляющий ответ padNone |
TPdfAsyncTaskWorker | Элемент работы — указатель на метод, получающий токен отмены своей задачи |
TPdfAsyncTaskReply | Завершающий обратный вызов — указатель на метод, принимающий неизменяемый снимок результата задачи |
TPdfAsyncTaskResult | TaskId, State, Priority, моменты QueuedAtTick, StartedAtTick и CompletedAtTick, пара ошибки worker ErrorMessage и ErrorClassName, CancellationReason с сообщением и изолированный ReplyErrorMessage |
IPdfAsyncTask | Дескриптор отправленной задачи с Cancel, учитывающим таймаут WaitFor, атомарным Snapshot и свойствами Id, State, Priority, Token и IsCompleted |
TPdfAsyncExecutorStats | Ёмкость, текущая нагрузка, пиковая глубина очереди и накопительные счётчики отправленных, успешных, отменённых, неудачных и отклонённых задач |
EPdfAsyncQueueFull | Возбуждается методом Submit, когда ограниченная очередь не может принять ещё одну задачу |
EPdfAsyncExecutorShutdown | Возбуждается методом Submit после начала остановки исполнителя |
TPdfAsyncExecutor | Многоразовый фиксированный пул рабочих потоков с ограниченной очередью, четырьмя приоритетными кольцами O(1), кооперативной отменой задач, статистикой и корректной остановкой |
| Function | Description |
|---|---|
PdfAsyncTick | Возвращает монотонную миллисекундную метку, используемую в метаданных future и исполнителя |
PdfAsyncTickDelta | Вычисляет защитное значение прошедших миллисекунд и возвращает ноль для отсутствующих или идущих в обратном порядке меток |
PdfNextAsyncId | Возвращает локальный для процесса положительный идентификатор, общий для 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 с другим приоритетом потока выбрасывает ENotSupportedException ещё до запуска worker
Используйте TPdfAsyncExecutor для повторяющейся или всплесковой работы, чтобы задачи переиспользовали фиксированный набор потоков вместо создания отдельного потока на каждую операцию
Положительная ёмкость очереди даёт детерминированное обратное давление, а ноль оставляет очередь неограниченной; выполняющиеся задачи не занимают слоты очереди
Приоритетное планирование строго между очередями и FIFO внутри каждой, поэтому приберегайте papCritical и papHigh для действительно чувствительной к задержкам работы
WaitForIdle обрабатывает синхронизированные обратные вызовы при вызове из главного потока, позволяя ответам padSynchronize завершиться без дедлока при остановке
Каждый источник таймаута держит один лёгкий поток ожидания до отмены или истечения, поэтому при создании очень большого числа короткоживущих дедлайнов предпочтительнее общий таймер приложения или планировщик дедлайнов
Правила владения объектами PDFium остаются в силе: создавайте или изолируйте экземпляр TPdf для каждого параллельного worker и не изменяйте и не рендерьте один и тот же активный экземпляр документа параллельно
Исходные API IPdfCancellationToken, IPdfCancellationTokenSource, TPdfCancellationTokenSource.New и TPdfFuture<T>.Run остаются совместимыми на уровне исходного кода
Расширенные интерфейсы используйте только тогда, когда требуются структурированная диагностика, съёмные обратные вызовы, ожидание по таймауту или атомарное владение отменой
Обратные вызовы остаются указателями на методы, а не анонимными методами, поэтому тот же API компилируется в Delphi, C++Builder и Free Pascal