首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >TStringList线程安全吗?

TStringList线程安全吗?
EN

Stack Overflow用户
提问于 2016-08-06 17:48:52
回答 2查看 2.9K关注 0票数 3

可以在没有任何形式的同步的情况下从TStringList读取数据吗?例如,与主线程同步。

示例代码

代码语言:javascript
复制
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的访问

代码语言:javascript
复制
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;
EN

回答 2

Stack Overflow用户

发布于 2016-08-07 04:31:52

首先,没有一个TStringList是线程安全的.

其次,尝试这样做对于一个低级别的容器来说是个糟糕的主意,在绝大多数情况下,这种容器不会在多个线程之间共享。

第三,你提出的使其线程安全的天真代码远远不够。它远远不能使它真正的线程安全,这是问题的一部分,试图这样做泛化。

在你的问题中,你会问:

在没有任何形式的同步的情况下从TStringList读取数据可以吗?

是的没关系。事实上,这是首选的,因为它更有效率。

但是,如果数据是跨线程共享的,您可能会遇到问题。这就是为什么您应该尽量减少线程间共享的数据量(不仅仅是字符串列表)。如果您这样做,需要来共享数据,以一种适当控制的方式这样做。

在第3点展开

您的代码不是线程安全的原因是它没有保护所有您的数据不受共享访问。这是多线程开发中常见的误解:“我只需要用锁包装某些操作,一切都会好的。”

关键是,如果您的列表是共享的,您将:

  • 共享表示容器的结构。
  • --您正在共享数据成员(实际字符串)本身。
  • 在处理字符串时,这会更进一步,因为Delphi管理字符串的方式意味着它们可以(通过内部引用计数)在应用程序的一个完全不同的区域中与其他值相同的字符串共享。

虽然您建议的锁定策略可能适合您当前的需求,但它远非一般的线程安全。

结论

如果您想要编写线程安全代码,onus就在您的上:

  • 了解数据访问路径。
  • 尽量减少线程之间的共享(到目前为止,这是最划算的)。
  • 并实现安全共享数据的最佳策略(其中有许多选项,而且锁定在任何情况下都不一定是最佳的)。

侧纹

我在前面已经指出,您的锁定技术“可能适合您当前的需求”,因为我认为您并没有真正给出有关实际需求的指示。如果您有,那么您确实需要注意以下几点

在您介绍的代码中,使您的TStringList“线程安全”绝对没有好处。在循环中填充列表,在第二个循环中读取值。您完全不需要同时使用这些数据。

您的代码应该最接近多线程,这将是一个好主意,处理两个循环离开主线程,以避免阻塞UI。在这种情况下,后台线程应该而不是共享它的TStringList实例。并且可以简单地与主线程同步来报告结果(可能还有进度更新)。

通过不共享不需要共享的数据,您可以完全绕过对锁的需求。这将是不必要的开销。TStringList没有内置的“线程安全”机制,您可以感到高兴。

票数 16
EN

Stack Overflow用户

发布于 2016-08-06 18:02:40

不,它不是。TStringList内部没有任何机制,可以锁定例如.Add().GetStrings()

不幸的是,没有什么能像TThreadList那样内置,这是一个用于TList的线程安全包装器。但你可以自己轻松地建立起它。

下面是TStringList的同步装饰器的一个简单示例,因为我介绍了Add()的情况:

代码语言:javascript
复制
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;

将其应用于所有其他需要的方法应该很容易。

请记住,您必须先初始化关键部分,然后才能使用它,然后再删除它。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38807135

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档