Reputation: 1113
I have an application with 50 threads that do something and I want my procedure (btnTestClick) to wait until all threads are terminated. I've tried with global variable as counter and with WaitForMultipleObjects(threadCount, @threadArr, True, INFINITE);
but the procedure never waits for all threads to terminate.Here is how my thread looks like :
TClientThread = class(TThread)
protected
procedure Execute; override;
public
constructor create(isSuspended : Boolean = False);
end;
And here are the constructor and the execute procedure :
constructor TClientThread.create(isSuspended : Boolean);
begin
inherited Create(isSuspended);
FreeOnTerminate := True;
end;
procedure TClientThread.Execute;
var
begin
inherited;
criticalSection.Enter;
try
Inc(globalThreadCounter);
finally
criticalSection.Leave;
end;
end;
And my OnButtonClick is this :
procedure TMainForm.btnTestClick(Sender: TObject);
var
clientThreads : array of TClientThread;
i, clientThreadsNum : Integer;
begin
clientThreadsNum := 50;
SetLength(clientThreads, clientThreadsNum);
for i := 0 to Length(clientThreads) - 1 do begin // РЕДАКТИРАЙ !!
clientThreads[i] := TClientThread.Create(True);
end;
// here I will assign some variables to the suspended threads, but that's not important here
for i := 0 to Length(clientThreads) - 1 do begin
clientThreads[i].Start;
end;
WaitForMultipleObjects(clientThreadsNum, @clientThreads, True, INFINITE);
// do something after all threads are terminated
end;
Upvotes: 5
Views: 5099
Reputation: 612804
You code reads:
WaitForMultipleObjects(clientThreadsNum, @clientThreads, True, INFINITE);
where clientThreads
is of type:
array of TClientThread
Now, @clientThreads
is the address of the dynamic array. That is the address of a pointer to the first thread object. But you are expected to pass a pointer to the first thread handle, something utterly different. So instead you need to form a list of thread handles:
var
ThreadHandles: array of THandle;
....
SetLength(ThreadHandles, Length(clientThreads));
for i := 0 to high(clientThreads) do
ThreadHandles[i] := clientThreads[i].Handle;
WaitForMultipleObjects(clientThreadsNum, Pointer(ThreadHandles), True, INFINITE);
You would have discovered that your call to WaitForMultipleObjects
was incorrect had you checked the return value. A basic rule of Win32 programming, one that you should strive not to break, is that you check the values returned by function calls.
I believe that your call to WaitForMultipleObjects
will return WAIT_FAILED
. When that happens you can call GetLastError
to find out what went wrong. You should modify your code to perform proper error checking. Take good care to read the documentation to find out how to do so.
Upvotes: 16