Latar Belakang

Saya memiliki unit test di mana saya memeriksa apakah kode kode handler saya berkinerja baik selama stres multi-utas:

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;

Jika utas paralel gagal diselesaikan dalam waktu yang diharapkan, ada sesuatu yang salah dan cek saya gagal. Sayangnya jika tugas paralel macet, itu tidak pernah berakhir dan pengujian unit saya membeku karena rilis antarmuka bt di akhir rutinitas saya yang menunggu tugas paralel yang tidak pernah berakhir untuk diselesaikan.

Jadi saya perlu mematikan tugas paralel saya dengan cara jahat.

CATATAN 1: Ini adalah pengujian unit, saya tidak terlalu peduli dengan pembersihan utas: tetap ada sesuatu yang perlu diperbaiki jika pengujian unit gagal. Saya hanya tidak ingin seluruh unit test suite saya hang/freeze, tetapi cukup laporkan kegagalan dan lanjutkan dengan tes berikutnya di suite saya.

CATATAN 2: Numthreads(1) dapat dihilangkan atau jumlah utas yang berubah-ubah.

Inilah T:Bagaimana cara menghentikan tugas IOmniParallel secara paksa?

1
H.Hasenack 30 Juni 2020, 22:49

1 menjawab

Jawaban Terbaik

Oke, saya seharusnya melakukan penelitian yang lebih baik. Inilah solusi untuk satu utas latar belakang, cukup gunakan antarmuka IOmniTaskControl:

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;

Dan jika Anda ingin menjalankannya di beberapa sub-utas, Anda harus membungkusnya dalam 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;

Menggunakan penundaan/breakpoints di debugger saya, saya memverifikasi penanganan unit test (kesalahan) sekarang berfungsi seperti yang diharapkan. Ini termasuk kebocoran memori yang diharapkan karena utas yang dimatikan.

Saya masih merasa IOmniParallelTask harus memiliki metode Terminate yang mirip dengan yang ada di IOmniTask dan IOmniTaskGroup

1
H.Hasenack 30 Juni 2020, 20:32