可以在没有任何形式同步的情况下从 TStringList 读取数据吗?例如与主线程同步。
示例代码
var MyStringList:TStringList; //declared globally
procedure TForm1.JvThread1Execute(Sender: TObject; Params: Pointer);
var x:integer;
begin
for x:=0 to MaxInt do MyStringList.Add(FloatToStr(Random));
end;
procedure TForm1.ButtonClick(Sender: TObject);
var x:integer;
SumOfRandomNumbers:double;
begin
for x:=0 to MyStringList.Count-1 do
SumOfRandomNumbers:=SumOfRandomNumbers+StrToFloat(MyStringList.Strings[x]);
end;
或者我应该使用 EnterCticalSection 保护对 MyStringList 的访问
var MyStringList:TStringList; //declared globally
procedure TForm1.JvThread1Execute(Sender: TObject; Params: Pointer);
var x:integer;
begin
for x:=0 to MaxInt do
begin
EnterCriticalSection(MySemaphore);
MyStringList.Add(FloatToStr(Random));
LeaveCriticalSection(MySemaphore);
end;
end;
procedure TForm1.ButtonClick(Sender: TObject);
var x:integer;
SumOfRandomNumbers:double;
begin
for x:=0 to MyStringList.Count-1 do
begin
EnterCriticalSection(MySemaphore);
SumOfRandomNumbers:=SumOfRandomNumbers+StrToFloat(MyStringList.Strings[x]);
LeaveCriticalSection(MySemaphore);
end;
end;
最佳答案
首先,没有TStringList
不是线程安全的。
其次,对于在绝大多数情况下不会在多个线程之间共享的低级容器来说,尝试这样做将是一个糟糕的主意。
第三,您建议使其成为线程安全的简单代码是远远不够的。它远远没有达到真正的线程安全——这是尝试这样做的问题的一部分。
在您提出的问题文本中:
Is it ok to read data from TStringList without any form of synchronisation?
是的,没关系。事实上,这是首选,因为它更有效。
但是,如果数据跨线程共享,您可能会遇到问题。这就是为什么您应该最小化跨线程共享的数据量(而不仅仅是字符串列表)。如果您确实需要共享数据,请以适当控制的方式进行。
<小时/>扩展第 3 点
您的代码不是线程安全的原因是它无法保护您的所有数据免遭共享访问。这是多线程开发中常见的误解:“我只需要用锁包装某些操作就可以了。”
重点是,如果您的列表被共享,您将:
- 共享代表容器的结构。
- 并且您正在共享数据成员(实际字符串)本身。
- 在处理字符串时,这更进一步,因为 Delphi 管理字符串的方式意味着它们可以与应用程序完全不同区域中具有相同值的其他字符串共享(通过内部引用计数)。
虽然您提出的锁定策略可能可能适合您当前的要求,但它远非一般的线程安全。
结论
如果您想编写线程安全代码,您有责任:
- 了解数据访问路径。
- 最大限度地减少线程之间的共享(迄今为止最划算的做法)。
- 并实现安全共享数据的最佳策略(其中有很多选项,并且锁定在任何情况下都不能保证是最佳策略)。
旁注
我之前指出,您的锁定技术仅“可能适合您当前的要求”,因为我不相信您确实给出了关于您的指示真实强>要求。如果您有,那么您确实需要注意以下几点:
在您提供的代码中,制作 TStringList
绝对没有任何好处。 “线程安全”。您在循环中填充列表,并在第二个循环中读取值。您完全没有执行任何操作来同时使用数据。
最接近多线程的代码是:最好在主线程之外处理两个循环,以避免阻塞 UI。在这种情况下,后台线程不应共享其 TStringList
实例。并且可以简单地与主线程同步以报告结果(以及可能的进度更新)。
通过不共享不需要共享的数据,您可以完全绕过对锁的需要。它们将是不必要的开销。你可以很高兴TStringList
没有内置的“线程安全”机制。
关于multithreading - TStringList 线程安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38807135/