问题
Background
I have a unit test in which I check if my handler code code performs well during multi-thread stress:
procedure TestAppProgress.TestLoopedAppProgressRelease_SubThread;
begin
var bt:=Parallel.ParallelTask.NumTasks(1).NoWait.Execute(
procedure
begin
SetWin32ThreadName('TestLoopedAppProgressRelease_SubThread');
RunLoopedAppProgressRelease;
end
);
lSuccess:=bt.WaitFor(cRunLoopTimerMilliSecs*2);
if not lSuccess then
bt.Terminate; // emergency termination, unit test failed <<< How do I do this?
Check(lSuccess,'Failed to finish within expected time');
end;
in case the parallel thread fails to complete within the expected time, something is wrong and my check fails. Unfortunately if the parallel task hangs, it never gets to an end and my unit test freezes because of the release of the bt interface at the end of my routine that waits for the never ending parallel task to complete.
So I need to shutdown my parallel task the evil way.
NOTE 1: It's a unit test, I don't really care about the thread cleanup: something needs to be fixed anyway if the unit test fails. I just don't want my entire unit test suite to hang/freeze, but simply report the failure and to continue with the next test in my suite.
NOTE 2: The Numthreads(1) could be omitted or an arbitrary number of threads.
Here's the Q:How can I terminate an IOmniParallel
task forcibly?
回答1:
Okay, I should have done better research. Here's the solution for a single background thread, just use the IOmniTaskControl
interface:
procedure TestAppProgress.TestLoopedAppProgressRelease_SubThread;
begin
var lTask:=CreateTask(
procedure (const aTask:IOmniTask)
begin
RunLoopedAppProgressRelease;
end,
'TestLoopedAppProgressRelease_SubThread'
);
lTask.Run;
var lSuccess:=lTask.WaitFor(cRunLoopTimerMilliSecs*2);
if not lSuccess then
lTask.Terminate; // emergency termination, unit test failed
Check(lSuccess,'Failed to finish within expected time');
end;
And in case you want to run it in multiple subthreads, you need to wrap it up in an IOmniTaskGroup
:
procedure TestAppProgress.TestLoopedAppProgressRelease_MultiSubThread;
const cThreads=4;
begin
var lTaskGroup:=CreateTaskGroup;
for var i:=1 to cThreads do
begin
var lTask:=CreateTask(
procedure (const aTask:IOmniTask)
begin
RunLoopedAppProgressRelease;
end,
'TestLoopedAppProgressRelease_SubThread '+i.ToString
);
lTaskGroup.Add(lTask);
end;
lTaskGroup.RunAll;
var lSuccess:=lTaskGroup.WaitForAll(cRunLoopTimerMilliSecs*2);
if not lSuccess then
lTaskGroup.TerminateAll; // emergency termination, unit test failed
Check(lSuccess,'Failed to finish within expected time');
end;
Using delays/breakpoints in my debugger I verfied the unit test (error) handling now works as expected. This is including expected memory leaks due to the killed threads.
I still feel IOmniParallelTask
should have an Terminate
method similar to the ones in IOmniTask
and IOmniTaskGroup
来源:https://stackoverflow.com/questions/62665155/emergency-termination-of-omnithread-iomniparalleltask