我一直在尝试追踪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
。问题是它们尚未初始化; 这些是线程启动后的下一行代码:
Device := Dev;
NumBytesRead := 0;
SetLength(Report, Dev.Caps.InputReportByteLength);
我认识到这是一种竞争条件;用户在生产环境中遇到崩溃的可能性非常低,因此保留这种竞争条件崩溃可能是无害的。
但是我有没有想错呢?我有没有忽略什么?调用以下内容:
BeginThread(nil, 0, @ThreadProc, Pointer(Self), Flags, FThreadID);
为什么线程不能立即开始运行?这真的是一个故意添加到JVCL中的竞争条件回归吗?有关此事是否有些秘密,请保留HTML标记。
CreateSuspended(False);
这使得它成为比以下代码更加正确的代码:
CreateSuspended(True);
...
FDataThread.Resume;
?
After having been burned by mistakenly calling
TMyThread.Create(False)
我把它记在脑海里,认为从来不正确。让线程立即启动(当您必须初始化值时)是否有任何有效的用途?