2016-11-17 31 views
4

,我们可以调用同一个线程在几个时间MyThread.waitfor。如果线程已经终止没有问题,这将不会引发任何异常并立即返回(正常行为)。这是Android下TThread的bug吗?在Windows

在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,关闭过程的任何进一步的通话将failled

我觉得这是必须这样写:

function TThread.WaitFor: LongWord; 
{$ELSEIF Defined(POSIX)} 
begin 
    if FThreadID = 0 then exit; 
    ... 
end; 
{$ENDIF POSIX} 

什么你认为 ?我需要在emb上打开一个bug请求吗?

回答

5

pthread_join文档说:

与先前已未定义行为的联合结果线程加入。

这解释了为什么TThread采取措施避免调用未定义的行为。

有缺陷的设计?这是有争议的。如果我们要考虑这个课程的设计,让我们像设计师一样扩大讨论范围。 Windows线程可以由多个不同的线程等待。 pthreads不是这种情况。链接的文档也说:

如果多个线程同时尝试用同一线程的加入,结果是不确定的。

所以我不认为Embarcadero可以合理地在Posix平台上实现与Windows上已经存在的相同的行为。正如你所描述的那样,他们肯定会从同一个线程中重复等待。那么,他们必须坚持线程返回值,以便WaitFor可以返回它。但那只会让你在那里分手,反正也不会很有用。毕竟,你为什么会再次从同一个线程中等待呢?

我怀疑FThreadID设置为0,以避免未定义的行为并以更稳健的方式失败。但是,如果多个线程调用WaitFor然后有一个数据竞争如此不确定的行为仍然是可能的。

如果我们想成为慈善然后我们就可以

离开这些具体细节一侧,很显然,如果WaitFor通过调用pthread_join然后跨平台的不同行为实现是必然的。 Embarcadero公司试图对准TThread实现各个平台,但由于平台的功能不同,它们不能完全等同。 Windows提供了比pthread更丰富的线程原语。

如果英巴卡迪诺选择了不同的路径,他们可以完美地对齐平台,但需要在Posix上更加努力。它可以复制Windows的行为存在,但这种特殊的方法将不得不比其他pthread_join东西来实现。我想你将不得不适应pthreads的不同功能。在pthread中,仅仅为了方便起见,包含等待线程的能力。如果您确实想要支持重复等待,您最好等待事件或条件变量。另一方面,您可能只是重新创建您的代码,以确保您只需等待一次。

所以,总而言之,如果还没有人,你应该提出一个Embarcadero的问题。他们可能会考虑支持你的方案。在系统中有一个问题是值得的。但是,如果他们选择不做任何事情并且证明这一点,那么不要感到惊讶,因为无法克服更广泛的平台差异,并且班级需要额外的复杂性来支持您的毫无意义的用例。有一点我希望我们都可以同意,但是TThread.WaitFor的Delphi文档应该涵盖这些问题。

+0

感谢大卫,但如果你看waitfor的实现,他们设置FThreadID:= 0,所以任何进一步调用waitfor可以检查FThreadID = 0,如果是立即返回? – loki

+0

他们可以这样做,我想。但是他们不能有多个等待的线程。无论如何,你为什么要从同一个线程中等待两次? –

+0

它不是真的关于多线程,但多功能..例如,当你有几个功能(这是所有从主线程调用),需要等待线程完成之前继续(这些功能都是独立的)。那么所有的测试MyThread.waitfor。当然,我可以更新所有的功能,如果不是MyThread.checkTerminated然后MyThread.waitfor – loki