德尔福(Delphi):线程是否应该被创建为“不被挂起"? [英] Delphi: Should a thread ever be created "not suspended"?

查看:121
本文介绍了德尔福(Delphi):线程是否应该被创建为“不被挂起"?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直试图追踪Jedi VCL JvHidControllerClass.pas中的内存泄漏,我在源历史记录中发现了这一变化:

I've been trying to track down a memory leak in Jedi VCL's JvHidControllerClass.pas, which i came across this change in the source history:

旧版本:

constructor TJvHidDeviceReadThread.CtlCreate(const Dev: TJvHidDevice);
begin
  inherited Create(True);
  Device := Dev;
  NumBytesRead := 0;
  SetLength(Report, Dev.Caps.InputReportByteLength);
end;

当前版本:

constructor TJvHidDeviceReadThread.CtlCreate(const Dev: TJvHidDevice);
begin
  inherited Create(False);
  Device := Dev;
  NumBytesRead := 0;
  SetLength(Report, Dev.Caps.InputReportByteLength);
end;

根据经验,我发现如果您创建的线程未暂停:

From experience, i've discovered that if you create a thread not suspended:

inherited Create(False);

然后该线程立即开始运行.在这种情况下,它将尝试访问尚未初始化的对象:

then the thread immediately starts running. In this case it will attempt to access an object that has not been initialized yet:

procedure TJvHidDeviceReadThread.Execute;
begin
   while not Terminated do
   begin
     FillChar(Report[0], Device.Caps.InputReportByteLength, #0);
     if Device.ReadFileEx(Report[0], Device.Caps.InputReportByteLength, @DummyReadCompletion) then

立即尝试填充Report,并访问对象Device.问题在于它们尚未初始化.这些是线程启动后的 next 行:

right away trying to fill Report, and access the object Device. Problem is that they haven't been initialized yet; those are the next lines after the thread has started:

  Device := Dev;
  NumBytesRead := 0;
  SetLength(Report, Dev.Caps.InputReportByteLength);

我意识到这是比赛条件;而且用户在生产中发生崩溃的机会非常低,因此离开种族崩溃可能是无害的.

i realize this is a race condition; and the chances of a user experiencing a crash in production are pretty low, so it's probably harmless to leave the race-crash.

但是我要离开吗?我想念什么吗?是否打电话:

But am i way off? Am i missing something? Does calling:

BeginThread(nil, 0, @ThreadProc, Pointer(Self), Flags, FThreadID);

无法立即关闭线程并立即运行吗?这真的是(有意)添加到JVCL中的种族条件回归吗?

not start a thread off and running right away? Is this really a race condition regression that was (intentionally) added to JVCL? Is there some secret about

CreateSuspended(False);

使其成为正确代码:

CreateSuspended(True);
...
FDataThread.Resume;

?

被误叫烧毁后

TMyThread.Create(False)

我将其存档为从不.是否有让线程立即启动(必须初始化值时)的有效用法?

i've filed it in my brain as never correct. Is there any valid use for letting a thread start right away (when you have to initialize values)?

推荐答案

这是TThread的Delphi 5实现的基本设计缺陷.基础Windows线程在TThread的构造函数中启动.导致您所描述的种族.

This is a basic design flaw with the Delphi 5 implementation of TThread. The underlying Windows thread is started in the constructor of TThread. Which leads to the race that you describe.

在Delphi 6版本的RTL中,更改了线程启动机制.从Delphi 6开始,线程在TThread.AfterConstruction中启动.并在构造函数完成后运行.这将使您的代码竞赛免费.

In the Delphi 6 version of the RTL, the thread start mechanism was changed. From Delphi 6 onwards, the thread is started in TThread.AfterConstruction. And that runs after the constructor completes. That would render your code race free.

在Delphi 6和更高版本中,基础Windows线程是在TThread构造函数中创建的,但是使用CREATE_SUSPENDED标志是挂起的.然后,在AfterConstruction中,只要TThread.FCreateSuspendedFalse,线程就会恢复.

In Delphi 6 and later, the underlying Windows thread is created in the TThread constructor, but is created suspended using the CREATE_SUSPENDED flag. Then in AfterConstruction, so long as TThread.FCreateSuspended is False, the thread is resumed.

解决Delphi 5中问题的一种方法是最后调用继承的构造函数.像这样:

One way to work around the issue in Delphi 5 is to call the inherited constructor last. Like this:

constructor TJvHidDeviceReadThread.CtlCreate(const Dev: TJvHidDevice);
begin
  Device := Dev;
  NumBytesRead := 0;
  SetLength(Report, Dev.Caps.InputReportByteLength);
  inherited Create(False);
end;

我知道这有点丑陋.

因此,创建挂起的线程并在构造函数完成后重新开始的方法可能更好.该方法反映了RTL如何解决Delphi 6及更高版本中的问题.

So, your approach of creating the thread suspended and resuming once the constructor has completed is probably better. That approach mirrors how the RTL solves the problem in Delphi 6 and up.

这篇关于德尔福(Delphi):线程是否应该被创建为“不被挂起"?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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