Ian*_*oyd 9 delphi multithreading delphi-5 jvcl
我一直试图追踪Jedi VCL中的内存泄漏JvHidControllerClass.pas,我在源历史中遇到了这种变化:
旧版本:
constructor TJvHidDeviceReadThread.CtlCreate(const Dev: TJvHidDevice);
begin
inherited Create(True);
Device := Dev;
NumBytesRead := 0;
SetLength(Report, Dev.Caps.InputReportByteLength);
end;
Run Code Online (Sandbox Code Playgroud)
目前的修订:
constructor TJvHidDeviceReadThread.CtlCreate(const Dev: TJvHidDevice);
begin
inherited Create(False);
Device := Dev;
NumBytesRead := 0;
SetLength(Report, Dev.Caps.InputReportByteLength);
end;
Run Code Online (Sandbox Code Playgroud)
根据经验,我发现如果你创建一个未挂起的线程:
inherited Create(False);
Run Code Online (Sandbox Code Playgroud)
然后线程立即开始运行.在这种情况下,它将尝试访问尚未初始化的对象:
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
Run Code Online (Sandbox Code Playgroud)
马上尝试填充Report,并访问该对象Device.问题是它们尚未初始化; 这些是线程启动后的下一行:
Device := Dev;
NumBytesRead := 0;
SetLength(Report, Dev.Caps.InputReportByteLength);
Run Code Online (Sandbox Code Playgroud)
我意识到这是一种竞争条件; 用户在生产中遇到崩溃的可能性非常低,因此离开竞赛失败可能是无害的.
但我离开了吗?我错过了什么吗?打电话:
BeginThread(nil, 0, @ThreadProc, Pointer(Self), Flags, FThreadID);
Run Code Online (Sandbox Code Playgroud)
没有立即启动线程并立即运行?这是否真的是(有意)添加到JVCL的竞争条件回归?是否有一些秘密
CreateSuspended(False);
Run Code Online (Sandbox Code Playgroud)
这使它成为正确的代码:
CreateSuspended(True);
...
FDataThread.Resume;
Run Code Online (Sandbox Code Playgroud)
?
被错误地打电话烧了之后
TMyThread.Create(False)
Run Code Online (Sandbox Code Playgroud)
我把它归于我的大脑,因为它永远不正确.是否有任何有效的用途让线程立即启动(当你必须初始化值时)?
Dav*_*nan 12
这是Delphi 5实现的基本设计缺陷TThread.底层Windows线程在构造函数中启动TThread.这导致你描述的种族.
在Delphi 6版本的RTL中,线程启动机制已更改.从Delphi 6开始,线程启动TThread.AfterConstruction.并且在构造函数完成后运行.这将使您的代码免费竞争.
在Delphi 6及更高版本中,底层Windows线程是在TThread构造函数中创建的,但是使用该CREATE_SUSPENDED标志创建了挂起.然后AfterConstruction,只要TThread.FCreateSuspended是False,线程就会恢复.
解决Delphi 5中的问题的一种方法是最后调用继承的构造函数.像这样:
constructor TJvHidDeviceReadThread.CtlCreate(const Dev: TJvHidDevice);
begin
Device := Dev;
NumBytesRead := 0;
SetLength(Report, Dev.Caps.InputReportByteLength);
inherited Create(False);
end;
Run Code Online (Sandbox Code Playgroud)
相当难看,我知道.
因此,创建线程暂停并在构造函数完成后恢复的方法可能更好.这种方法反映了RTL如何解决Delphi 6及更高版本中的问题.
| 归档时间: |
|
| 查看次数: |
1692 次 |
| 最近记录: |