创建一个线程(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。
等待(几乎)任意数量的工作线程的解决方案(仅限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.