2012-01-12 94 views
25

常規的「線程安全」的MSDN文檔爲StringBuilder指出,部分:是.NET的StringBuilder的線程安全

...任何實例成員不能保證線程安全...

但這句話感覺就像已經被複制,並在框架粘貼,幾乎每一個類:

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

然而,由加文·普格這些博客文章提到的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/

此外,StringBuilder的由反射透露來源,並附帶意見 在SSCLI來源,也提出了許多實施方面的考慮以確保線程安全:

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

有沒有人有更深入的瞭解StringBuilder實例是否可以安全地在多個併發線程之間共享?

回答

21

絕對沒有;這裏是一個簡單的例子,從4.0通過反射器解除:

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

該屬性只處理調用者,而不是線程安全;這絕對是不是線程安全的。

更新:看他引用的源代碼,這顯然不是當前的.NET 4.0代碼庫(比較幾種方法)。也許他正在談論一個特定的.NET版本,或者可能是XNA - 但它通常是而不是。 4.0 StringBuilder不具有具有 a m_currentThread字段,加文的來源材料使用;有一個提示(一個未使用的常量ThreadIDField),它使用存在,但不再...。


如果你想有一個直接反證 - 4.0上運行此;它很可能會給出錯誤的長度(我在4k區域看到了一些,在2k區域看到了一些 - 它應該恰好爲5000),但其他一些方法(例如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 < 1000; i++) sb.Append("a"); 

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

最多3.5個'String.Builder'仍包含線程檢查代碼。有關更多詳細信息,請參閱http://stackoverflow.com/a/3564934/3205。 – skolima 2012-10-18 15:42:53

5

該文檔的重點是給你保證。在這種情況下,實例成員不保證是線程安全的,因此您應該將其視爲線程安全的,因此依賴於外部同步方法。

,有些事情可能線程是實現細節從而可以也許會改變從框架的一個版本到下一個,或從一個執行到下(其實有很多這樣的細節變化在框架版本中; Eric Lippert有一些帖子詳細介紹了其中的一些)。不要依賴它。

(換句話說:不要寫代碼一種實施方式,它編寫針對接口和合同它是類的元數據和其在這種情況下的文件)

0

MSDN documentation

任何公共靜態此類型的成員(Visual Basic中的Shared)是 線程安全的。任何實例成員不保證是線程 安全。