【发布时间】:2013-07-19 14:17:15
【问题描述】:
我一直在尝试追踪 Jedi 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;
根据经验,我发现如果您创建一个线程不暂停:
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
立即尝试填充Report,并访问对象Device。问题是它们还没有被初始化;这些是线程启动后的 next 行:
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)
我在我的脑海中将它归档为从不正确。让线程立即启动(当您必须初始化值时)是否有任何有效用途?
【问题讨论】:
-
哇!!! D5 上的 JVCL!我虽然在我退出它并停止维护 D5 兼容性后它被关闭了。好怀旧的感觉……
-
@Arioch'The 不要太怀旧;它是 2009 年的 JVCL 3.x。严格来说,它是 Richard Marquand 从 2005 年开始的原始 HidController 类;我帮了一点忙。 JVCL采用的版本经历了巨大的"jcl-ifying";但没有真正的区别;但从技术上讲,我使用的是理查德的版本;所以我可以修复 FastMM 捕获的 use-after-free 崩溃。
标签: multithreading delphi delphi-5 jvcl