在Android上,它有所不同,如果我们调用两次MyThread.waitfor,那么我们将在第二次尝试中使用"没有这样的过程"。
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}
发生错误是因为在调用waitfor时他们设置了FThreadID:= 0所以当然任何进一步的调用都会失败
我认为必须写成:
function TThread.WaitFor: LongWord;
{$ELSEIF Defined(POSIX)}
begin
if FThreadID = 0 then exit;
...
end;
{$ENDIF POSIX}
你怎么看?我需要在emb?打开错误请求吗?
答案 0 :(得分:5)
pthread_join
的文档说:
加入先前已加入的线程会导致未定义的行为。
这解释了为什么TThread
采取措施避免调用未定义的行为。
设计中是否存在缺陷?这是值得商榷的。如果我们要考虑这门课程的设计,那就像设计师必须拓宽讨论范围一样。 Windows线程可以由多个不同的线程等待。 pthreads的情况并非如此。链接的文档还说:
如果多个线程同时尝试使用同一个线程加入,则结果是未定义的。
所以我不认为Embarcadero可以合理地在Posix平台上实现与Windows上已有的相同的行为。可以肯定的是,正如您所描述的那样,他们可以从同一个线程重复等待特殊情况。好吧,他们必须坚持线程返回值,以便WaitFor
可以返回它。但那只会让你在那里分道扬and,反正也不会有用。毕竟,为什么你会再次从同一个线程中等待?
我怀疑FThreadID
设置为0以避免未定义的行为并以更健壮的方式失败。但是,如果多个线程调用WaitFor
,则存在数据争用,因此仍然可以进行未定义的行为。
如果我们想要慈善,那么我们可以
将这些具体细节留给一方,很明显,如果通过调用WaitFor
来实现pthread_join
,则跨平台的不同行为是不可避免的。 Embarcadero试图调整每个平台的TThread
实现,但由于平台功能不同,它们不能完全等效。 Windows提供了比pthreads更丰富的线程原语集。
如果Embarcadero选择了不同的路径,他们可以完美地对齐平台,但需要在Posix上更加努力。可以在那里复制Windows行为,但是这个特定方法必须使用pthread_join
之外的其他方法来实现。
虽然面对现实,但我认为你必须适应pthreads的不同功能。在pthreads中,仅仅为了方便起见,包括在线程上等待的能力。如果你真的想支持重复等待,你最好等待事件或条件变量。另一方面,您可能只是重新创建代码以确保只等待一次。
总而言之,如果没有Embarcadero,你应该提出一个问题。他们可能会考虑支持您的方案。并且它值得在系统中出现问题。但是,如果他们选择不做任何事情并且因为更广泛的平台差异无法克服,并且课堂上需要额外的复杂性来支持您的有些无意义的用例,那就不要感到惊讶。我希望我们可以同意的一件事是,TThread.WaitFor
的Delphi文档应该涵盖这些问题。