没有任何形式的同步,从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;
或者我应该使用EnterCiticalSection保护对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;
答案 0 :(得分:16)
首先,TStringList
不是线程安全的
其次,尝试制作它对于低级容器来说是一个糟糕的想法,在绝大多数情况下,它不会在多个线程之间共享。
第三,你提出的使线程安全的天真代码是不够的。它远远没有使它真正的线程安全 - 这是尝试这样做的一般问题的一部分。
在你的问题文本中,你问:
没有任何形式的同步从TStringList读取数据是否可以?
是的,没关系。事实上,这是首选,因为它更有效。
然而 ,如果跨线程共享数据,则可能会遇到问题。这就是为什么你应该最小化跨线程共享的数据量(不仅仅是字符串列表)。如果您需要分享数据,请以适当的控制方式进行。
您的代码不是线程安全的原因是它无法保护您的数据免受共享访问的 所有 。这是多线程开发中常见的误解:“我只需要使用锁包装某些操作,一切都会好的。”
关键是,如果您的列表是共享的,那么您就是:
虽然您提出的锁定策略可能可能适合您的当前要求,但它远非一般的线程安全。
如果您想编写线程安全的代码, onus就在您上:
我之前说过,你的锁定技术只有“可能适合你当前的要求”,因为我不相信你真的给出了关于你 真实的指示 要求。如果你有,那么确实需要注意以下:
在您提供的代码中,使TStringList
“线程安全”绝对没有任何好处。您在循环中填充列表,并在第二个循环中读取值。您完全没有使用数据并发。
您的代码最接近多线程的是:从主线程处理两个循环以避免阻止UI 是个好主意。在这种情况下,后台线程应 NOT 共享其TStringList
实例。并且可以简单地与主线程同步以报告结果(以及可能的进度更新)。
通过共享不共享 的数据,您可以完全绕过对锁的需求。它们将是不必要的开销。而且你很高兴TStringList
没有拥有内置的“线程安全”机制。
答案 1 :(得分:1)
不,不是。 TStringList
内部没有机制可锁定,例如.Add()
或.GetStrings()
。
不幸的是,没有像TThreadList
那样内置的东西,它是TList
的线程安全包装器。但是你可以自己轻松地构建它。
以下是TStringList的同步装饰器的一个简单示例,其中我介绍了Add()
的情况:
TThreadStringList = class
private
FStringList: TStringList;
FCriticalSection: TRtlCriticalSection;
// ...
public
function Add(const S: string): Integer;
// ...
end;
// ...
TThreadStringList.Add(const S: string): Integer;
begin
EnterCriticalSection(FCriticalSection);
try
Result:= Add(S);
finally
LeaveCriticalSection(FCriticalSection);
end;
end;
将其应用于您需要的所有其他方法应该很容易。
请记住,您必须初始化关键部分,然后才能使用,然后删除。< / p>