gpt4 book ai didi

multithreading - Delphi - 从第二个线程更新全局字符串

转载 作者:行者123 更新时间:2023-12-03 14:43:38 25 4
gpt4 key购买 nike

我正在 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com