Multithreading Delphi:是否应该创建一个线程;“未暂停”吗;?
我一直在努力追踪绝地VCL的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
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()
。