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 | 응답 디스패치와 워커 ThreadPriority를 위한 RunEx 설정입니다 |
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을 통해 기존 synchronized 응답 동작을 유지하고 RunEx로 구성 가능한 디스패치를 더하는 fire-and-forget 헬퍼입니다 |
| 타입 | 설명 |
|---|---|
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 | executor 종료가 시작된 뒤 Submit이 발생시킵니다 |
TPdfAsyncExecutor | 상한이 있는 큐, 네 개의 O(1) 우선순위 링, 협력적 작업 취소, 통계, 우아한 종료를 갖춘 재사용 가능한 고정 워커 풀입니다 |
| 함수 | 설명 |
|---|---|
PdfAsyncTick | future와 executor 메타데이터가 사용하는 단조 증가 밀리초 틱을 반환합니다 |
PdfAsyncTickDelta | 방어적으로 경과 밀리초를 계산하며, 없거나 역전된 틱에는 0을 반환합니다 |
PdfNextAsyncId | future, 콜백 등록, executor 작업이 공유하는 프로세스 로컬 양수 ID를 반환합니다 |
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이 발생합니다
반복되거나 몰리는 작업에는 TPdfAsyncExecutor를 사용하세요. 작업이 연산마다 스레드를 하나씩 만드는 대신 고정된 스레드 집합을 재사용합니다
큐 용량을 양수로 두면 결정론적 백프레셔를 제공하고 0이면 큐가 무한해집니다. 실행 중인 작업은 큐 슬롯을 소비하지 않습니다
우선순위 스케줄링은 레인 사이에서는 엄격하고 레인 안에서는 FIFO이므로, papCritical과 papHigh는 실제로 지연에 민감한 작업을 위해 남겨 두세요
메인 스레드에서 호출하면 WaitForIdle이 synchronized 콜백을 처리하므로, padSynchronize 응답이 종료 교착 없이 마무리될 수 있습니다
각 시간 초과 소스는 취소나 만료까지 대기 스레드 하나를 가볍게 점유하므로, 아주 많은 수명 짧은 기한을 만든다면 공유 애플리케이션 타이머나 기한 스케줄러 쪽이 낫습니다
PDFium 객체 소유 규칙은 그대로 적용됩니다. 동시 워커마다 TPdf 인스턴스를 만들거나 분리하고, 같은 활성 문서 인스턴스를 동시에 변경하거나 렌더링하지 마세요
기존 IPdfCancellationToken, IPdfCancellationTokenSource, TPdfCancellationTokenSource.New, TPdfFuture<T>.Run API는 소스 수준 호환성을 유지합니다
구조화된 진단, 제거 가능한 콜백, 시간 초과 대기, 원자적 취소 소유권이 필요할 때만 확장 인터페이스를 사용하세요
콜백은 익명 메서드가 아니라 메서드 포인터이므로, 같은 API를 Delphi, C++Builder, Free Pascal에서 모두 컴파일할 수 있습니다