可以在没有任何形式的同步的情况下从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保护对EnterCiticalSection的访问
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;发布于 2016-08-07 04:31:52
首先,没有一个TStringList是线程安全的.
其次,尝试这样做对于一个低级别的容器来说是个糟糕的主意,在绝大多数情况下,这种容器不会在多个线程之间共享。
第三,你提出的使其线程安全的天真代码远远不够。它远远不能使它真正的线程安全,这是问题的一部分,试图这样做泛化。
在你的问题中,你会问:
在没有任何形式的同步的情况下从TStringList读取数据可以吗?
是的没关系。事实上,这是首选的,因为它更有效率。
但是,如果数据是跨线程共享的,您可能会遇到问题。这就是为什么您应该尽量减少线程间共享的数据量(不仅仅是字符串列表)。如果您这样做,需要来共享数据,以一种适当控制的方式这样做。
在第3点展开
您的代码不是线程安全的原因是它没有保护所有您的数据不受共享访问。这是多线程开发中常见的误解:“我只需要用锁包装某些操作,一切都会好的。”
关键是,如果您的列表是共享的,您将:
虽然您建议的锁定策略可能适合您当前的需求,但它远非一般的线程安全。
结论
如果您想要编写线程安全代码,onus就在您的上:
侧纹
我在前面已经指出,您的锁定技术“可能适合您当前的需求”,因为我认为您并没有真正给出有关实际需求的指示。如果您有,那么您确实需要注意以下几点
在您介绍的代码中,使您的TStringList“线程安全”绝对没有好处。在循环中填充列表,在第二个循环中读取值。您完全不需要同时使用这些数据。
您的代码应该最接近多线程,这将是一个好主意,处理两个循环离开主线程,以避免阻塞UI。在这种情况下,后台线程应该而不是共享它的TStringList实例。并且可以简单地与主线程同步来报告结果(可能还有进度更新)。
通过不共享不需要共享的数据,您可以完全绕过对锁的需求。这将是不必要的开销。TStringList没有内置的“线程安全”机制,您可以感到高兴。
发布于 2016-08-06 18:02:40
不,它不是。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;将其应用于所有其他需要的方法应该很容易。
请记住,您必须先初始化关键部分,然后才能使用它,然后再删除它。
https://stackoverflow.com/questions/38807135
复制相似问题