on windows, we can call several time MyThread.waitfor on the same thread. if the thread is already terminated no problem this will not raise any exception and return immediatly (normal behavior).
on Android, it's different, if we call twice MyThread.waitfor then we will have an exception on the second try with "No such process".
function TThread.WaitFor: LongWord;
{$ELSEIF Defined(POSIX)}
var
X: Pointer;
ID: pthread_t;
begin
if FExternalThread then
raise EThread.CreateRes(@SThreadExternalWait);
ID := pthread_t(FThreadID);
if CurrentThread.ThreadID = MainThreadID then
while not FFinished do
CheckSynchronize(1000);
FThreadID := 0;
X := @Result;
CheckThreadError(pthread_join(ID, X));
end;
{$ENDIF POSIX}
the error is made because on call to waitfor they set FThreadID := 0 so off course any further call will failled
i think it's must be written like :
function TThread.WaitFor: LongWord;
{$ELSEIF Defined(POSIX)}
begin
if FThreadID = 0 then exit;
...
end;
{$ENDIF POSIX}
what do you think ? did i need to open a bug request at emb ?
The documentation for pthread_join
says:
Joining with a thread that has previously been joined results in undefined behavior.
This explains why TThread
takes steps to avoid invoking undefined behavior.
Is there defect in the design? That's debatable. If we are going to consider the design of this class, let's broaden the discussion, as the designers must. A Windows thread can be waited on by multiple different threads. That's not the case for pthreads. The linked documentation also says:
If multiple threads simultaneously try to join with the same thread, the results are undefined.
So I don't think Embarcadero could reasonably implement the same behaviour on Posix platforms as already exists on Windows. For sure they could special case repeated waits from the same thread, as you describe. Well, they'd have to persist the thread return value so that WaitFor
could return it. But that would only get you part way there, and wouldn't be very useful anyway. After all, why would you wait again from the same thread?
I suspect that FThreadID
is set to 0 in an effort to avoid the undefined behaviour and fail in a more robust way. However, if multiple threads call WaitFor
then there is a data race so undefined behaviour is still possible.
If we were trying to be charitable then we could
Leaving those specific details to one side, it is clear that if WaitFor
is implemented by calling pthread_join
then differing behaviour across platforms is inevitable. Embarcadero have tried to align the TThread
implementations for each platform, but they cannot be perfectly equivalent because the platform functionality differs. Windows offers a richer set of threading primitives than pthreads.
If Embarcadero had chosen a different path they could have aligned the platforms perfectly but would have needed to work much harder on Posix. It is possible to replicate the Windows behaviour there, but this particular method would have to be implemented with something other than pthread_join
.
Facing the reality though, I think you will have to adapt to the different functionality of pthreads. In pthreads the ability to wait on a thread is included merely as a convenience. You would do better to wait on an event or a condition variable instead, if you really do want to support repeated waits. On the other hand you might just re-create your code to ensure you only wait once.
So, to summarise, you should probably raise an issue with Embarcadero, if there isn't one already. It is possible that they might consider supporting your scenario. And it's worth having an issue in the system. But don't be surprised if they choose to do nothing and justify that because of the wider platform differences that cannot be surmounted, and the extra complexity needed in the class to support your somewhat pointless use case. One thing I expect we can all agree on though is that the Delphi documentation for TThread.WaitFor
should cover these issues.