15

很久以前,当我开始在 Delphi 中使用线程时,我通过TThread.Resume在构造函数的末尾调用来让线程自己启动,并且仍然这样做,如下所示:

constructor TMyThread.Create(const ASomeParam: String);
begin
  inherited Create(True);
  try
    FSomeParam:= ASomeParam;
    //Initialize some stuff here...
  finally
    Resume;
  end;
end;

从那时起,Resume已被弃用,Start取而代之的是。但是,Start只能从线程外部调用,不能从构造函数内部调用。

我继续使用Resume如上所示设计我的线程,尽管我知道它已被弃用 - 只是因为我不想Start从线程外部调用。我觉得不得不打电话有点乱:

FMyThread := TMyThread.Create(SomeParamValue);
FMyThread.Start;

问题:进行此更改的原因是什么?我的意思是Resume,他们希望我们使用的使用有什么问题Start

编辑在 Sedat 的回答之后,我想这真的取决于在构造函数中线程何时真正开始执行。

4

1 回答 1

13

简短而精辟的答案是因为TThread类的作者不相信开发人员会阅读或理解文档。:)

暂停和恢复线程是仅适用于非常有限数量的用例的合法操作。事实上,这个有限的数字本质上是“一个”: 调试器

不良品

它被认为是不可取的(至少可以说)的原因是,如果一个线程被挂起而(例如)它拥有某个其他同步对象(例如互斥锁或信号量等)的锁,则可能会出现问题。

这些同步对象专门设计用于确保一个线程相对于访问共享资源的其他线程的安全操作,因此中断和干扰这些机制很可能会导致问题。

出于惊人的相似原因,调试器需要一种工具来直接挂起线程,而不管这些机制如何。

例如,考虑断点涉及线程上的隐式(或者您甚至可以说是显式)“挂起”操作。如果调试器在到达断点时暂停线程,那么它还必须暂停进程中的所有其他线程,因为否则它们将抢先执行可能会干扰调试器可能被要求执行的许多低级任务的工作然后做。

调试器的强大武器

调试器不能“注入”良好的、礼貌的同步对象和机制来请求这些其他线程以协调的方式挂起自己,与其他一些已经被随意停止(通过断点)的线程协调。调试器别无选择,只能对线程进行强力武装,而这正是 Suspend/Resume API 的用途。

它们适用于您需要停止线程“现在。无论您在做什么我不在乎,只需停止! ”的情况。然后,然后说“好的,你现在可以继续你以前在做什么,不管它是什么。 ”。

表现良好的线程彼此表现良好

显然,这不是行为良好的线程在正常操作中与其他线程交互的方式(如果它希望保持“正常”操作的状态而不产生各种问题)。在那些正常情况下,一个线程非常关心并且应该关心那些其他线程正在做什么,并确保它不会干扰,使用适当的同步技术与那些其他线程进行协调。

在这些情况下,恢复线程的合法用例同样被简化为一种单一模式。也就是说,您已经创建并初始化了一个您不希望立即运行的线程,而是希望在稍后的某个时间点在某个其他线程的控制下开始执行。

但是,一旦启动了新线程,必须使用适当的同步技术来实现与其他线程的后续同步,而不是通过蛮力暂停它。

开始与暂停/恢复

因此,决定Suspend / Resume在通用线程类上没有真正的位置(实现调试器的人仍然可以直接调用 Windows API),而是提供了更合适的“启动”机制。

希望很明显,即使这个Start机制使用了与之前不推荐使用的 Resume 方法完全相同的 API,但目的却完全不同。

于 2016-03-15T04:06:29.747 回答