“Emergency” termination of omnithread IOmniParallelTask

这一生的挚爱 提交于 2021-02-08 06:50:21

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!