Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading Delphi:是否应该创建一个线程;“未暂停”吗;?_Multithreading_Delphi_Delphi 5_Jvcl - Fatal编程技术网

Multithreading Delphi:是否应该创建一个线程;“未暂停”吗;?

Multithreading Delphi:是否应该创建一个线程;“未暂停”吗;?,multithreading,delphi,delphi-5,jvcl,Multithreading,Delphi,Delphi 5,Jvcl,我一直在努力追踪绝地VCL的JvHidControllerClass.pas中的内存泄漏,我在源代码历史记录中遇到了这样的变化: 旧版本: constructor TJvHidDeviceReadThread.CtlCreate(const Dev: TJvHidDevice); begin inherited Create(True); Device := Dev; NumBytesRead := 0; SetLength(Report, Dev.Caps.InputRepor

我一直在努力追踪绝地VCL的
JvHidControllerClass.pas
中的内存泄漏,我在源代码历史记录中遇到了这样的变化:

旧版本:

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;
当前版本:

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;
根据经验,我发现如果创建的线程未挂起:

inherited Create(False);
然后线程立即开始运行。在这种情况下,它将尝试访问尚未初始化的对象:

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
立即尝试填写
报告
,并访问对象
设备
。问题是它们还没有被初始化;以下是线程启动后的下一行:

  Device := Dev;
  NumBytesRead := 0;
  SetLength(Report, Dev.Caps.InputReportByteLength);
我意识到这是一种竞赛状态;而且用户在生产中遇到崩溃的可能性非常低,所以离开比赛崩溃可能是无害的

但我离这里很远吗?我错过什么了吗?打电话是否:

BeginThread(nil, 0, @ThreadProc, Pointer(Self), Flags, FThreadID);
不是马上就开始脱线跑步吗?这真的是(有意)添加到JVCL中的种族条件回归吗?有什么秘密吗

CreateSuspended(False);
这使其成为正确的代码:

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

在被误打电话烧死之后

TMyThread.Create(False)

我在脑子里把它写成了“永远都不对”。让线程立即启动(当您必须初始化值时)有什么有效的用途吗?

这是Delphi 5实现的
TThread
的一个基本设计缺陷。底层Windows线程在
TThread
的构造函数中启动。这导致了你所描述的比赛

在Delphi6版本的RTL中,线程启动机制已更改。从Delphi6开始,线程在
TThread.AfterConstruction
中启动。这将在构造函数完成后运行。这将使您的代码无竞争

在Delphi 6及更高版本中,底层Windows线程是在
TThread
构造函数中创建的,但使用
CREATE\u suspended
标志创建时挂起。然后在
AfterConstruction
中,只要
TThread.FCreateSuspended
False
,线程就会恢复

在Delphi5中解决此问题的一种方法是最后调用继承的构造函数。像这样:

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


因此,创建挂起线程并在构造函数完成后恢复的方法可能更好。这种方法反映了RTL如何在Delphi6及更高版本中解决问题。

Wow!!!D5上的JVCL!我想在我退出它并停止维护D5兼容性后,它被关闭了。这种怀旧的感觉…@Arioch'The不要太怀旧;这是2009年的JVCL 3.x。严格来说,这是理查德·马坎德从2005年开始的HidController课程;我帮了一点忙。JVCL采用的版本经历了巨大的“jcl化”;但是没有真正的区别;但从技术上讲,我使用的是理查德的版本;所以我可以在FastMM捕获的免费崩溃后修复使用。这就解释了+历史课1分!我通常的做法是在线程执行中直接实例化/销毁。如果您需要使用COM(比如ADO)之类的东西,那么无论如何都必须这样做。所以,在现实中,每当我写一个线程时,我从来没有在create/destroy中实现任何创建或销毁,或者任何与此相关的东西。(+1)@Jerry在需要在创建者和线程之间进行通信之前,这没关系“在Delphi 5中解决问题的一种方法是最后调用继承的构造函数”-另一种方法是复制D6+中
TThread
的功能。在构造函数中使用
CreateSuspended=True调用
inherited
(顺序无关紧要),然后重写
AfterConstruction()
调用
Resume()
。而不是要求构造线程对象的调用代码手动调用
Resume()