Absolutely not; here's a simple example lifted from 4.0 via reflector:
[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;
}
The attribute just handles callers, not thread-safety; this is absolutely not thread-safe.
Update: looking at the source he references, this is clearly not the current .NET 4.0 code-base (comparing a few methods). Perhaps he is talking about a particular .NET version, or maybe XNA - but it is not the case in general. The 4.0 StringBuilder
does not have a m_currentThread
field, which Gavin's source material uses; there's a hint (an unused constant ThreadIDField
) that it used to exist, but... no longer.
If you want a direct disproof - run this on 4.0; it will most likely give the wrong length (I've seen a few in the 4k region, a few in the 2k region - it should be exactly 5000), but some other Append
methods (Append(char)
for example) tend more likely to throw exceptions, depending on timing:
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);
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…