多个连续线程上的TThread.WaitFor

问题描述 投票:2回答:1

创建一个线程(TThreadStarter),它将创建许多工作线程,并且必须等待它们完成才能继续。它必须在Linux和Windows下运行。

以下方法似乎是一种解决方案。但这是一个好的吗?你会以不同的方式做吗?

1)创建并将所有线程放入一个数组中,然后运行该数组并调用Start。

2)然后再次运行数组并调用WaitFor,以便调用线程的执行停止,直到所有线程都完成。

procedure TThreadStarter.Execute;
var i1:integer;
begin
  for i1:=1 to WORK_THREAD_COUNT do ThreadArray[i1].Start;
  for i1:=1 to WORK_THREAD_COUNT do ThreadArray[i1].WaitFor;

  ..Do some work

end;

我使用Lazarus和FreePascal。

multithreading delphi freepascal lazarus
1个回答
0
投票

等待(几乎)任意数量的工作线程的解决方案(仅限Windows)。

从你的WaitForThreads(不是普通的主线程)调用MainWorkerThread函数,并传入一个你想要等待的所有线程句柄的数组。

interface

uses
  Windows, SysUtils, Classes;

type
  THandleDynArray = array of THandle;

  TMaximum_Wait_Objects_Handles = array[0..MAXIMUM_WAIT_OBJECTS - 1] of THandle;

  EMaximum_Handles_Exceeded = class(Exception);

  TThreadWaitForThreads = class(TThread)
  strict private
    FarrHandle: TMaximum_Wait_Objects_Handles;
    FThreadWaitCount: 0..MAXIMUM_WAIT_OBJECTS;
  protected
    procedure Execute; override;
  public
    procedure AddHandle(Handle: THandle); overload;
    procedure AddHandle(HandleArray: THandleDynArray); overload;
    procedure ClearHandles;
  end;

procedure WaitForThreads(const Handles: THandleDynArray);

implementation

procedure WaitForThreads(const Handles: THandleDynArray);
var
  Wait_Result: cardinal;
  arrHandle: TMaximum_Wait_Objects_Handles;
  arrWaitThreads: array[0..MAXIMUM_WAIT_OBJECTS - 1] of TThreadWaitForThreads;
  WaitThreadsCount, i: integer;
begin
  if Length(Handles) <= 0 then
    exit;    

  if Length(Handles) > MAXIMUM_WAIT_OBJECTS then
  begin
    WaitThreadsCount := Length(Handles) div MAXIMUM_WAIT_OBJECTS;

    for i := 0 to WaitThreadsCount - 1 do
    begin
      arrWaitThreads[i] := TThreadWaitForThreads.Create(true);
      arrHandle[i] := arrWaitThreads[i].Handle;

      arrWaitThreads[i].AddHandle(Copy(Handles, MAXIMUM_WAIT_OBJECTS * i, MAXIMUM_WAIT_OBJECTS));
    end;

    try
      if Length(Handles) mod MAXIMUM_WAIT_OBJECTS > 0 then
        Move(Handles[MAXIMUM_WAIT_OBJECTS * WaitThreadsCount], arrHandle[WaitThreadsCount], (Length(Handles) - WaitThreadsCount * MAXIMUM_WAIT_OBJECTS) * SizeOf(THandle));

      for i := 0 to WaitThreadsCount - 1 do
        arrWaitThreads[i].Resume;

      repeat
        Wait_Result := WaitForMultipleObjectsEx(WaitThreadsCount + Length(Handles) - WaitThreadsCount * MAXIMUM_WAIT_OBJECTS, @arrHandle, true, 10, true);
        Application.ProcessMessages;
      until ((Wait_Result <> WAIT_TIMEOUT)
        and (Wait_Result <> WAIT_IO_COMPLETION));

    finally
      for i := 0 to WaitThreadsCount - 1 do
      begin
        arrWaitThreads[i].Terminate; // terminating all WaitThreads to be on the safe side
        arrWaitThreads[i].Free;
      end;
    end;
  end
  else
  begin
    repeat
      Wait_Result := WaitForMultipleObjectsEx(Length(Handles), @Handles[0], true, 10, true);
      Application.ProcessMessages;
    until ((Wait_Result <> WAIT_TIMEOUT)
      and (Wait_Result <> WAIT_IO_COMPLETION));
  end;
end;

{ TThreadWaitForThreads }

procedure TThreadWaitForThreads.AddHandle(Handle: THandle);
begin
  if FThreadWaitCount < MAXIMUM_WAIT_OBJECTS then
  begin
    FarrHandle[FThreadWaitCount] := Handle;
    Inc(FThreadWaitCount);
  end
  else
    raise EMaximum_Handles_Exceeded.Create('You can only wait for ' + IntToStr(MAXIMUM_WAIT_OBJECTS) + ' Threads!');
end;

procedure TThreadWaitForThreads.AddHandle(HandleArray: THandleDynArray);
begin
  if FThreadWaitCount + Length(HandleArray) <= MAXIMUM_WAIT_OBJECTS then
  begin
    Move(HandleArray[0], FarrHandle[FThreadWaitCount], SizeOf(THandle) * Length(HandleArray));
    Inc(FThreadWaitCount, Length(HandleArray));
  end
  else
    raise EMaximum_Handles_Exceeded.Create('You want to wait for ' + IntToStr(FThreadWaitCount + Length(HandleArray)) + ' threads, but you can only wait for ' + IntToStr(MAXIMUM_WAIT_OBJECTS) + '!');
end;

procedure TThreadWaitForThreads.ClearHandles;
begin
  FThreadWaitCount := 0;
  ZeroMemory(@FarrHandle, SizeOf(FarrHandle));
end;

procedure TThreadWaitForThreads.Execute;
var
  Wait_Result: cardinal;
begin
  if FThreadWaitCount = 0 then
    exit;

  repeat
    Wait_Result := WaitForMultipleObjectsEx(FThreadWaitCount, @FarrHandle, true, 10, true);
  until ((Wait_Result <> WAIT_TIMEOUT)
    and (Wait_Result <> WAIT_IO_COMPLETION))
    or Terminated;

  ClearHandles;
end;

end.
© www.soinside.com 2019 - 2024. All rights reserved.