在windows上,我们可以在同一个线程上多次调用MyThread.waitfor。如果线程已经终止没问题,这不会引发任何异常并立即返回(正常行为)。

在 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 打开错误请求吗?

最佳答案

pthread_join 的文档说:



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

设计是否有缺陷?这是有争议的。如果我们要考虑这个类的设计,让我们扩大讨论范围,设计师必须这样做。一个 Windows 线程可以被多个不同的线程等待。 pthread 的情况并非如此。链接的文档还说:



所以我不认为 Embarcadero 可以合理地在 Posix 平台上实现与 Windows 上已经存在的相同的行为。当然,正如您所描述的,他们可以在特殊情况下从同一线程重复等待。好吧,他们必须保留线程返回值,以便 WaitFor 可以返回它。但这只会使您达到目标,而且无论如何也不会很有用。毕竟,你为什么要从同一个线程再次等待?

我怀疑 FThreadID 设置为 0 是为了避免未定义的行为并以更健壮的方式失败。但是,如果多个线程调用 WaitFor 则存在数据竞争,因此仍然可能存在未定义的行为。

如果我们想变得慈善,那么我们可以

将这些具体细节放在一边,很明显,如果 WaitFor 是通过调用 pthread_join 来实现的,那么跨平台的不同行为是不可避免的。 Embarcadero 已尝试为每个平台对齐 TThread 实现,但它们不能完全等效,因为平台功能不同。 Windows 提供了比 pthread 更丰富的线程原语集。

如果 Embarcadero 选择了不同的路径,他们可以完美地对齐平台,但需要在 Posix 上更加努力地工作。可以在那里复制 Windows 行为,但是必须使用 pthread_join 以外的其他方法来实现此特定方法。

面对现实,我认为您将不得不适应 pthread 的不同功能。在 pthreads 中,等待线程的能力仅仅是为了方便。如果您确实想支持重复等待,最好等待事件或条件变量。另一方面,您可能只是重新创建代码以确保您只等待一次。

因此,总而言之,您可能应该向 Embarcadero 提出问题,如果还没有的话。他们可能会考虑支持您的方案。值得在系统中出现问题。但是,如果他们选择什么都不做并证明其合理性,请不要感到惊讶,因为无法克服更广泛的平台差异,并且类中需要额外的复杂性来支持您有些无意义的用例。我希望我们都同意的一件事是 TThread.WaitFor 的 Delphi 文档应该涵盖这些问题。

关于android - 这是android下TThread的bug吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40665972/

10-11 20:22