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 | Ustrukturyzowany powód zakończenia obejmujący żądania użytkownika, przekroczenia czasu, powiązaną pracę, zamknięcie, pracę zastąpioną i anulowanie zdefiniowane przez aplikację |
EPdfOperationCancelled | Wyjątek anulowania z zachowanym oryginalnym Reason i komunikatem na potrzeby diagnostyki |
IPdfCancellationToken | Kompatybilny token strony roboczej z odpytywaniem IsCancelled, RegisterCallback, ThrowIfCancelled i obsługą wyjątków |
IPdfCancellationTokenSource | Kompatybilne źródło strony właściciela z Token i idempotentnym Cancel |
IPdfCancellationRegistration | Stabilna rejestracja wywołania zwrotnego z Id, IsRegistered i bezpiecznym wątkowo Unregister |
IPdfCancellationTokenEx | Rozszerzony token z metadanymi anulowania, licznikami wywołań zwrotnych, usuwalną rejestracją wywołań i oczekiwaniem opartym na zdarzeniach |
IPdfCancellationTokenSourceEx | Rozszerzone źródło właściciela z atomowym TryCancel, CancelWithReason i silnie typowanym TokenEx |
TPdfCancellationTokenSource | Bezpieczna wątkowo implementacja źródła tworzona przez New, NewEx lub NewTimeout |
PdfNoCancellationToken | Współdzielony token, który nigdy się nie anuluje i pozwala nie alokować źródła dla pracy, której nie można anulować |
| Type | Description |
|---|---|
TPdfFutureStatus | Stan wyniku: pfsSuccess, pfsCancelled lub pfsFailure |
TPdfFutureDispatchMode | Polityka odpowiedzi: pfdSynchronize wysyła odpowiedź do wątku głównego, pfdWorkerThread wywołuje ją na wątku roboczym, a pfdNone wycisza odpowiedź |
TPdfFutureOptions | Ustawienia RunEx dla dystrybucji odpowiedzi i ThreadPriority wątku roboczego |
TPdfFutureResult<T> | Koperta ukończenia z Value i HasValue, Status, parą ErrorMessage i ErrorClassName, CancellationReason, OperationId, StartedAtTick i CompletedAtTick, pomocnikami statusu oraz ElapsedMilliseconds |
TPdfFutureWorker<T> | Wskaźnik metody roboczej, który otrzymuje token anulowania i zwraca wynik w tle |
TPdfFutureReply<T> | Wskaźnik metody wywołania zwrotnego otrzymujący ukończone TPdfFutureResult<T> |
TPdfFutureThread<T> | Typ wątku wsparcia kompilatora używany przez TPdfFuture<T>; konstruowany przez Create lub uwzględniające opcje CreateEx, a aplikacje normalnie wywołują Run lub RunEx |
TPdfFuture<T> | Pomocnik fire-and-forget, który przez Run zachowuje pierwotne zachowanie synchronizowanej odpowiedzi, a przez RunEx dodaje konfigurowalną dystrybucję |
| Type | Description |
|---|---|
TPdfAsyncPriority | Cztery tory pobierania od papLow do papCritical, z kolejnością FIFO wewnątrz każdego toru |
TPdfAsyncTaskState | Cykl życia zadania: patsQueued, patsRunning, patsSucceeded, patsCancelled lub patsFailed |
TPdfAsyncDispatchMode | Dystrybucja odpowiedzi przez padWorkerThread, padSynchronize lub padNone, aby wyciszyć odpowiedź |
TPdfAsyncTaskWorker | Wskaźnik metody elementu pracy, który otrzymuje swój token anulowania zadania |
TPdfAsyncTaskReply | Wskaźnik metody wywołania ukończenia otrzymujący niemodyfikowalną migawkę wyniku zadania |
TPdfAsyncTaskResult | TaskId, State, Priority, czas QueuedAtTick, StartedAtTick i CompletedAtTick, para błędów roboczych ErrorMessage i ErrorClassName, CancellationReason z komunikatem oraz izolowany ReplyErrorMessage |
IPdfAsyncTask | Uchwyt zgłoszonego zadania z Cancel, uwzględniającym limit czasowy WaitFor, atomowym Snapshot oraz właściwościami Id, State, Priority, Token i IsCompleted |
TPdfAsyncExecutorStats | Pojemność, bieżące obciążenie, szczytowa głębokość kolejki oraz skumulowane liczniki zgłoszeń, sukcesów, anulowań, błędów i odrzuceń |
EPdfAsyncQueueFull | Zgłaszany przez Submit, gdy ograniczona kolejka nie może przyjąć kolejnego zadania |
EPdfAsyncExecutorShutdown | Zgłaszany przez Submit po rozpoczęciu zamknięcia egzekutora |
TPdfAsyncExecutor | Wielokrotnego użytku stała pula wątków z ograniczoną kolejką, czterema pierścieniami priorytetów O(1), kooperatywnym anulowaniem zadań, statystykami i łagodnym zamknięciem |
| Function | Description |
|---|---|
PdfAsyncTick | Zwraca monotoniczny tik w milisekundach używany przez metadane future i egzekutora |
PdfAsyncTickDelta | Wylicza defensywną wartość upływu czasu w milisekundach i zwraca zero dla tików brakujących lub wstecznych |
PdfNextAsyncId | Zwraca lokalny dla procesu dodatni identyfikator współdzielony przez future, rejestracje wywołań zwrotnych i zadania egzekutora |
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;
Kompilacje Delphi dla POSIX zachowują wartości opcji TThreadPriority tpIdle, tpLowest, tpLower, tpNormal, tpHigher, tpHighest i tpTimeCritical dla zgodności ze źródłem, ale RTL platformy obsługuje wyłącznie domyślną ścieżkę planowania. tpNormal korzysta z tej ścieżki; skonstruowanie future z innym priorytetem wątku zgłasza ENotSupportedException przed uruchomieniem pracownika
Używaj TPdfAsyncExecutor dla pracy powtarzalnej lub skokowej, aby zadania korzystały ze stałego zestawu wątków zamiast tworzyć jeden wątek na operację
Dodatnia pojemność kolejki daje deterministyczne backpressure, a zero pozostawia kolejkę bez ograniczeń; uruchomione zadania nie zużywają miejsc w kolejce
Harmonogramowanie priorytetów jest ścisłe między torami i FIFO wewnątrz toru, więc rezerwuj papCritical i papHigh dla pracy naprawdę wrażliwej na opóźnienia
WaitForIdle obsługuje wywołania zsynchronizowane, gdy jest wywoływane z wątku głównego, co pozwala odpowiedziom padSynchronize się zakończyć bez zakleszczenia przy zamykaniu
Każde źródło limitu czasu posiada jeden lekki wątek oczekujący do momentu anulowania lub upływu terminu, więc przy tworzeniu bardzo dużej liczby krótkotrwałych terminów lepszy jest współdzielony czasomierz aplikacji albo harmonogram terminów
Reguły własności obiektów PDFium nadal obowiązują: twórz lub izoluj instancję TPdf na każdego współbieżnego pracownika i nie modyfikuj ani nie renderuj tej samej aktywnej instancji dokumentu współbieżnie
Pierwotne API IPdfCancellationToken, IPdfCancellationTokenSource, TPdfCancellationTokenSource.New i TPdfFuture<T>.Run pozostają zgodne na poziomie źródeł
Rozszerzonych interfejsów używaj tylko wtedy, gdy wymagana jest ustrukturyzowana diagnostyka, usuwalne wywołania zwrotne, oczekiwanie z limitem czasu lub atomowa własność anulowania
Wywołania zwrotne pozostają wskaźnikami metod, a nie metodami anonimowymi, więc to samo API kompiluje się w Delphi, C++Builderze i Free Pascalu