- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在 Delphi (XE) 中尝试多线程,并且在主 VCL 线程和第二个工作线程之间使用全局变量时遇到了问题。
我的项目涉及第二个工作线程,它扫描一些文件,并使用当前文件名更新全局变量字符串。然后通过主 VCL 线程上的计时器拾取该全局变量,并更新状态栏。
我注意到它偶尔会出现“无效指针操作”...或“内存不足”或工作线程停止响应(可能死锁)。
因此,我创建了一个测试应用程序来识别并大大增加出错的可能性,以便我可以看到发生了什么。
type
TSyncThread = class(TThread)
protected
procedure Execute; override;
end;
var
Form11: TForm11;
ProgressString : String;
ProgressCount : Int64;
SyncThread : TSyncThread;
CritSect : TRTLCriticalSection;
implementation
{$R *.dfm}
procedure TForm11.StartButtonClick(Sender: TObject);
begin
Timer1.Enabled := true;
SyncThread := TSyncThread.Create(True);
SyncThread.Start;
end;
procedure TForm11.StopbuttonClick(Sender: TObject);
begin
Timer1.Enabled := false;
SyncThread.Terminate;
end;
procedure TForm11.Timer1Timer(Sender: TObject);
begin
StatusBar1.Panels[0].Text := 'Count: ' + IntToStr(ProgressCount);
StatusBar1.Panels[1].Text := ProgressString;
end;
procedure TSyncThread.Execute;
var
i : Int64;
begin
i := 0;
while not Terminated do begin
inc(i);
EnterCriticalSection(CritSect);
ProgressString := IntToStr(i);
ProgressCount := i;
LeaveCriticalSection(CritSect);
end;
end;
initialization
InitializeCriticalSection(CritSect);
finalization
DeleteCriticalSection(CritSect);
我将计时器间隔设置为 10 毫秒,以便它读取大量数据,同时工作线程全力运行更新全局变量字符串。果然,这个应用程序运行时几乎只持续一秒钟,就会出现上述错误。
我的问题是,VCL Timer中Global var的读操作是否需要运行在临界区? - 如果是这样,为什么?根据我的理解,这只是一次读取,并且写入已经在关键部分中运行,我不明白为什么它会遇到问题。如果我确实将计时器中的读取也放入关键部分 - 它工作正常......但我不高兴只是在不知道为什么的情况下这样做!
我是多线程新手,因此希望能帮助解释为什么这个简单的示例会导致各种问题,以及是否有更好的方法从工作线程访问字符串。
最佳答案
Delphi String 是在堆上分配的,它不是某处的静态缓冲区。变量本身只是一个指针。当您的读取线程访问一个字符串,并且同时该字符串被另一个线程释放时,会发生不好的事情。您正在访问已经释放的内存,可能会再次分配给其他东西,等等。
即使此字符串是静态缓冲区,更新操作也不是原子的,因此您可能正在使用此时正在更新的损坏的字符串(一半是新数据,一半是旧数据)。
因此,您需要使用与写入操作相同的临界区来保护读取操作。
关于multithreading - Delphi - 从第二个线程更新全局字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7779174/
我是一名优秀的程序员,十分优秀!