Which mechanism ensures a TTask terminates during a timeout in RAD Studio?
0 reputation · 05 Mar 2025, 08:02 UTC
0 reputation · 05 Mar 2025, 08:02 UTC
The Parallel Programming Library (PPL) in RAD Studio provides the ITask interface for background execution. While ITask.Cancel allows for the signaling of a task to stop, the worker thread must manually poll for this state to exit gracefully.
A challenge arises when implementing strict timeouts for asynchronous operations. Because ITask does not include a native timeout property, developers must coordinate external triggers, such as TTimer or TEvent, to initiate the cancellation process.
Given that ITask.Cancel does not forcibly terminate the thread, there is uncertainty regarding the most reliable way to ensure a blocked task actually yields control when a timeout occurs without risking resource exhaustion in the thread pool.
ITask polling?35275 reputation · 05 Mar 2025, 13:13 UTC
No built-in mechanism in RAD Studio System.Threading.TTask forces a task to terminate when a wait timeout expires. A timeout on the waiting side only stops the waiter; the task continues to run on the thread pool until it finishes or cooperates with cancellation.
The reliable pattern is cooperative cancellation coordinated with the wait timeout:
var
Src: TCancellationTokenSource;
Task: ITask;
begin
Src := TCancellationTokenSource.Create;
Task := TTask.Run(
procedure
begin
while not Src.Token.IsCancellationRequested do
begin
// work chunk
Src.Token.ThrowIfCancellationRequested;
end;
end,
Src.Token);
if Task.WaitFor(5000) = TTaskStatus.Running then
Src.Cancel;
end;
This ensures the waiter is released on timeout while giving the task a chance to unwind cleanly.
One diagnostic detail changes the recommendation: is the code inside the TTask owned by you and able to include cancellation checks, or is it third-party code with no cooperative points? Without cooperative points, safe termination is not achievable with TTask.
Use comments to ask for clarification. Post a solution as an answer.
35,275 reputation · 05 Mar 2025, 18:52 UTC
One practical nuance is that TTask.WaitFor with a timeout only changes the waiter's return status; it does not touch the task's cancellation state. If the timeout branch does not explicitly call Cancel on the associated TCancellationTokenSource, the task keeps running with no signal at all.
In practice this means the timeout path must both release the waiter and then signal cancellation, and the task body must avoid long, non-interruptible blocks. Blocking on a TEvent or synchronous I/O without periodic token checks will keep the pool thread occupied even after Cancel is raised.