使用TThread.Resume有什么问题? [英] What's wrong with using TThread.Resume?

查看:172
本文介绍了使用TThread.Resume有什么问题?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

很久以前,当我开始使用Delphi中的线程时,我正在通过在构造函数末尾调用 TThread.Resume 来开始自己的线程,像这样:

 构造函数TMyThread.Create(const ASomeParam:String); 
begin
继承Create(True);
try
FSomeParam:= ASomeParam;
//初始化一些东西在这里...
finally
简历;
结束
结束

此后,简历已被弃用有利于使用开始。但是,开始只能从线程外部调用,不能从构造函数内调用。



I继续使用 Resume 设计我的线程,如上所示,尽管我知道它已被弃用 - 只因为我不想调用开始从线程外面。我觉得有点麻烦要调用:

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

问题:这个更改的原因是什么?我的意思是说,使用 Resume ,他们希望我们使用开始而不是如此错误?



编辑在Sedat的回答之后,我想这真的取决于在构造函数中什么时候线程实际上开始执行。

解决方案

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



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



Undesirables





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

调试器需要直接的设施暂停线程,而不管这些机制是出人意料的类似原因。



考虑一个断点涉及一个隐式(或者你甚至可以说 ex plicit)在线程上挂起操作。如果调试器在到达断点时停止线程,那么它还必须暂停进程中的所有其他线程,正是因为它们将以其他方式进行前期的工作,这可能会干扰调试器可能被要求的许多低级任务然后执行。



调试器的强大功能



调试器不能注入漂亮,礼貌的同步对象以及要求这些其他线程以协调一致的方式挂起的机制,其中一些其他线程已被无意中停止(通过断点)。调试器没有选择,但是强制执行线程,这正是Suspend / Resume API的所在。



它们是情况,你需要停止线程现在,无论你在做什么,我不在乎,只是停止!。然后,再说可以,你现在可以随着你以前做的任何事情继续下去,无论是什么。



良好的线程相互之间相互作用



应该明显的是,这是一个很好的线程与其他线程交互的正常运作(如果要维持正常运作状态,不会产生各种各样的问题)。在这些正常情况下,线程非常 应该关心其他线程正在做什么,并确保它不会干扰,使用适当的同步技术来协调那些其他线程。



在这种情况下,恢复线程的合法用例同样可以简化为单一模式。这是你创建和初始化一个线程,您不希望立即运行,但在某些其他线程的控制下稍后时间执行开始执行。



但是,一旦新线程已经开始,与其他线程的后续同步必须使用正确的同步技术实现,



开始vs暂停/恢复



所以决定了暂停 / 恢复在通用线程类上没有真正的位置(实现调试器的人员仍然可以直接调用Windows API),而是更适合的开始机制提供。



希望很明显,尽管这个开始机制采用了与先前使用的已弃用的Resume方法完全相同的API,但目的是完全不同的>

Long ago, when I started working with threads in Delphi, I was making threads start themselves by calling TThread.Resume at the end of their constructor, and still do, like so:

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

Since then, Resume has been deprecated in favor to use Start instead. However, Start can only be called from outside the thread, and cannot be called from within the constructor.

I have continued to design my threads using Resume as shown above, although I know it's been deprecated - only because I do not want to have to call Start from outside the thread. I find it a bit messy to have to call:

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

Question: What's the reason why this change was made? I mean, what is so wrong about using Resume that they want us to use Start instead?

EDIT After Sedat's answer, I guess this really depends on when, within the constructor, does the thread actually begin executing.

解决方案

The short and pithy answer is because the authors of the TThread class didn't trust developers to read or to understand the documentation. :)

Suspending and resuming a thread is a legitimate operation for only a very limited number of use cases. In fact, that limited number is essentially "one": Debuggers

Undesirables

The reason it is considered undesirable (to say the least) is that problems can arise if a thread is suspended while (for example) it owns a lock on some other synchronization object such as a mutex or sempahore etc.

These synchronization objects are specifically designed to ensure the safe operation of a thread with respect to other threads accessing shared resources, so interrupting and interfering with these mechanisms is likely to lead to problems.

A debugger needs a facility to directly suspend a thread irrespective of these mechanisms for surprisingly similar reasons.

Consider for example that a breakpoint involves an implicit (or you might even say explicit) "suspend" operation on a thread. If a debugger halts a thread when it reaches a break-point then it must also suspend all other threads in the process precisely because they will otherwise race ahead doing work that could interfere with many of the low level tasks that the debugger might be asked to then do.

The Strong Arm of the Debugger

A debugger cannot "inject" nice, polite synchronization objects and mechanisms to request that these other thread suspend themselves in a co-ordinated fashion with some other thread that has been unceremoniously halted (by a breakpoint). The debugger has no choice but to strong-arm the threads and this is precisely what the Suspend/Resume API's are for.

They are for situations where you need to stop a thread "Right now. Whatever you are doing I don't care, just stop!". And later, to then say "OK, you can carry on now with whatever it was you were doing before, whatever it was.".

Well Behaved Threads Behave Well Toward Each Other

It should be patently obvious that this is not how a well-behaved thread interacts with other threads in normal operation (if it wishes to maintain a state of "normal" operation and not create all sorts of problems). In those normal cases a thread very much does and should care what those other threads are doing and ensure that it doesn't interfere, using appropriate synchronization techniques to co-ordinate with those other threads.

In those cases, the legitimate use case for Resuming a thread is similarly reduced to just one, single mode. Which is, that you have created and initialised a thread that you do not wish to run immediately but to start execution at some later point in time under the control of some other thread.

But once that new thread has been started, subsequent synchronization with other threads must be achieved using those proper synchronization techniques, not the brute force of suspending it.

Start vs Suspend/Resume

Hence it was decided that Suspend/Resume had no real place on a general purpose thread class (people implementing debuggers could still call the Windows API's directly) and instead a more appropriate "Start" mechanism was provided.

Hopefully it should be apparent that even though this Start mechanism employs the exact same API that the deprecated Resume method previously employed, the purpose is quite different.

这篇关于使用TThread.Resume有什么问题?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆