TStringList线程安全吗?

Ata*_*era 3 delphi multithreading tstringlist

没有任何形式的同步从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;
Run Code Online (Sandbox Code Playgroud)

或者我应该使用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;
Run Code Online (Sandbox Code Playgroud)

Dis*_*ned 16

首先,no TStringList不是线程安全的.
其次,尝试制作它对于低级容器来说是一个糟糕的想法,在绝大多数情况下,不会在多个线程之间共享.
第三,你提出的使线程安全的天真代码是不够的.它远远没有使它真正的线程安全 - 这是尝试这样做的一般问题的一部分.

在你的问题的文本中,你问:

没有任何形式的同步从TStringList读取数据是否可以?

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

但是,如果跨线程共享数据,则可能会遇到问题.这就是为什么你应该最小化跨线程共享的数据量(不仅仅是字符串列表).如果您确实需要共享数据,请以适当的控制方式进行.


扩展到第3点

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

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

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

虽然您提出的锁定策略可能适合您当前的要求,但它通常不是一般的线程安全的.

结论

如果你想编写线程安全的代码,那么onus就是你:

  • 了解数据访问路径.
  • 最小化线程之间的共享(到目前为止最好的降压).
  • 并实施安全共享数据的最佳策略(其中有许多选项,并且锁定不保证在任何情况下都是最佳的).

边注

我之前曾表示,您的锁定技术" 可能适合您当前的要求 ",因为我不相信您确实已经指出了您的实际要求.如果您有,那么您确实需要注意以下事项:

在您提供的代码中,使您的TStringList"线程安全" 绝对没有任何好处.您在循环中填充列表,并在第二个循环中读取值.你正在做绝对没有使用的数据并发.

你的代码最接近多线程的是:最好从主线程处理两个循环以避免阻塞UI.在这种情况下,后台线程应共享其TStringList实例.并且可以简单地与主线程同步以报告结果(以及可能的进度更新).

通过不共享不需要共享的数据,您可以完全绕过对锁的需求.它们将是不必要的开销.你可以很高兴TStringList 没有内置的"线程安全"机制.