【问题标题】:What's wrong with using TThread.Resume? [duplicate]使用 TThread.Resume 有什么问题? [复制]
【发布时间】:2016-03-14 23:44:10
【问题描述】:

很久以前,当我开始在 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 的回答之后,我想这真的取决于在构造函数中线程何时真正开始执行。

【问题讨论】:

  • finally 是错误的。如果引发异常怎么办?
  • 不管你做什么,最后总是错的。不要在析构函数即将运行的部分构造对象上执行线程。
  • 关于做什么:1. 删除 try/finally,2. 删除对 Resume 的调用,3. 将 False 传递给继承的构造函数。 4.让TThread.AfterConstruction在所有构造函数,甚至派生构造函数都完成后启动线程。
  • 查看源代码是如何实现的总是一个明智的决定。当前实现还尊重 Windows 2003 ServerCreateThread 调用中启动线程的不同行为
  • @SirRufo 我认为您可能错误地阅读了文档。在所有版本的window中,如果CREATE_SUSPENDED没有被传递,那么线程可能会在CreateThread返回之前开始执行。 Windows Server 2003 的特定行为在文档的上一段中进行了描述,并且与令牌和模拟有关。

标签: multithreading delphi deprecated tthread


【解决方案1】:

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

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

不受欢迎的

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

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

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

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

调试器的强大武器

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

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

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

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

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

但是一旦新线程启动,随后与其他线程的同步必须使用那些适当的同步技术来实现,不是蛮力暂停它的力量。

开始与暂停/恢复

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

希望很明显,即使此 Start 机制使用与之前已弃用的 Resume 方法完全相同的 API,但目的却大不相同。

【讨论】:

  • 我想说语言和框架的设计者学会了不相信有充分理由的用户。在不了解底层事物的情况下,将交给他的部分并做任何事情的平庸开发人员似乎超过了试图从头到尾学习整个系统的深思熟虑的软件工程师,以我的经验约为 10:1。因此,再多的警告也不够。如果有一个 TWorkerThread 就好了,但既然没有,开发人员就“凑合”了,弄得一团糟。然后他们责怪 RTL。
  • 即使有一个 TWorkerThread,也有办法访问它的句柄以传递给 OS Suspend/Resume API。你停在哪里? Windows API 不应该自己提供 Suspend/Resume API 吗?那么有人会如何明智地实现调试器呢?同样的不信任推理适用于 API 甚至语言提供的任何数量的设施和功能。
  • TThread 不适用于调试器。 Win32 API 可以很好地解决这个问题。
  • 如果不能期望开发人员正确使用 TThread 和暂停/恢复功能,那么他们怎么可能正确使用 Windows 暂停/恢复 API?在我看来,在没有成人监督的情况下,根本不应该允许他们靠近任何类型的编译器。 :) 一个坏工人指责他们的工具并不意味着这些工具需要“修复”。坏工人仍然会做不好的工作并继续责怪他们的工具。
  • 我不认为弃用是为了拯救不称职的程序员。我认为弃用是针对 x-plat。挂起/恢复只是 Windows 没有?
猜你喜欢
  • 2011-03-31
  • 2012-07-16
  • 2021-11-20
  • 2019-04-11
  • 2016-04-15
  • 2016-03-20
  • 2020-06-17
  • 1970-01-01
  • 2013-06-19
相关资源
最近更新 更多