【问题标题】:Delphi - Updating a global string from a second threadDelphi - 从第二个线程更新全局字符串
【发布时间】:2011-12-08 09:56:35
【问题描述】:

我在 Delphi (XE) 中试验多线程,但在 VCL 主线程和第二个工作线程之间使用全局变量时遇到了问题。

我的项目涉及第二个工作线程,它扫描一些文件,并使用当前文件名更新一个 globalvar 字符串。然后通过主 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 毫秒,以便它读取很多内容,而工作线程正在完全运行更新全局 var 字符串。果然这个应用程序在运行时只持续一秒钟就出现上述错误。

我的问题是,VCL Timer中Global var的读操作需要在临界区运行吗? - 如果是这样,为什么?据我了解,这只是一次读取,并且写入已经在关键部分运行,我看不出它为什么会遇到问题。如果我确实将计时器中的读取内容也放入关键部分 - 它工作正常....但我不高兴只是不知道为什么这样做!

我是多线程新手,所以如果能帮助我解释为什么这个简单的例子会导致各种问题,以及是否有更好的方法从工作线程访问字符串,我将不胜感激。

【问题讨论】:

  • 你知道你可以取消锁而只使用一个整数变量在线程之间共享数据吗? 64 位整数有点乱,但 32 位整数微不足道。

标签: multithreading delphi delphi-xe


【解决方案1】:

Delphi String 分配在堆上,它不是某处的静态缓冲区。变量本身只是一个指针。当您的阅读线程访问一个字符串时,同时这个字符串正被另一个线程释放,坏事发生了。您正在访问已经释放的内存,可能会再次分配给其他东西,等等。

即使此字符串是静态缓冲区,更新操作也不是原子的,因此您可能正在使用此时正在更新的损坏字符串(一半新数据和一半旧数据)。

因此,您需要使用与写入操作相同的临界区来保护您的读取操作。

【讨论】:

  • 谢谢! - 这是一个令人难以置信的快速回复,并详细解释了问题 - 正是我想要的。我总是喜欢知道发生了什么,而不是因为它有效就盲目地做某事。
猜你喜欢
  • 2018-02-25
  • 1970-01-01
  • 1970-01-01
  • 2020-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-06
相关资源
最近更新 更多