Dot-Net

.NET 的 StringBuilder 是執行緒安全的嗎

  • January 12, 2012

MSDN 文件的正常“執行緒安全”部分StringBuilder指出:

…不保證任何實例成員都是執行緒安全的…

但是這個語句感覺就像它已經被框架中的幾乎每個類都複製和粘貼了:

<http://msdn.microsoft.com/en-us/library/system.text.stringbuilder.aspx>

但是,Gavin Pugh 的這些部落格文章提到了以下執行緒安全行為StringBuilder

<http://www.gavpugh.com/2010/03/23/xnac-stringbuilder-to-string-with-no-garbage/>

<http://www.gavpugh.com/2010/04/01/xnac-avoiding-garbage-when-working-with-stringbuilder/>

此外,Reflector 透露的 StringBuilder 的原始碼,以及 SSCLI 原始碼中隨附的註釋,也提出了許多確保執行緒安全的實現注意事項:

<http://labs.developerfusion.co.uk/SourceViewer/browse.aspx?assembly=SSCLI&namespace=System.Text&type=StringBuilder>

有沒有人更深入地了解一個StringBuilder實例是否可以安全地在多個並發執行緒之間共享?

絕對不; 這是一個通過反射器從 4.0 提升的簡單範例:

[SecuritySafeCritical]
public StringBuilder Append(char value)
{
   if (this.m_ChunkLength &lt; this.m_ChunkChars.Length)
   {
       this.m_ChunkChars[this.m_ChunkLength++] = value;
   }
   else
   {
       this.Append(value, 1);
   }
   return this;
}

該屬性只處理呼叫者,而不是執行緒安全;這絕對不是執行緒安全的。

更新:查看他引用的原始碼,這顯然不是目前的 .NET 4.0 程式碼庫(比較幾種方法)。也許他在談論特定的 .NET 版本,或者可能是 XNA - 但一般情況並非如此。4.0StringBuilder沒有欄位,Gavin 的源材料使用該欄位;m_currentThread有一個提示(一個未使用的常量ThreadIDField)它曾經存在,但是……不再存在。


如果您想要直接反證 - 在 4.0 上執行它;它很可能會給出錯誤的長度(我在 4k 區域中看到了一些,在 2k 區域中看到了一些 - 它應該正好是 5000),但其他一些Append方法(Append(char)例如)更容易引發異常,具體取決於關於時間:

var gate = new ManualResetEvent(false);
var allDone = new AutoResetEvent(false);
int counter = 0;
var sb = new StringBuilder();
ThreadStart work = delegate
{
   // open gate when all 5 threads are running
   if (Interlocked.Increment(ref counter) == 5) gate.Set();
   else gate.WaitOne();

   for (int i = 0; i &lt; 1000; i++) sb.Append("a");

   if (Interlocked.Decrement(ref counter) == 0) allDone.Set();
};
for(int i = 0 ; i &lt; 5 ; i++)
{
   new Thread(work).Start();
}
allDone.WaitOne();
Console.WriteLine(sb.Length);

引用自:https://stackoverflow.com/questions/8831385