2012-01-12 11 views
25

La sección regular "Hilo de Seguridad" de la documentación de MSDN para StringBuilder establece que:de .NET flujos seguros StringBuilder

... los miembros de instancias no se garantiza que sea seguro para subprocesos ...

pero esta afirmación se siente como que ha sido copiado y pegado para casi todas las clases en el Marco:

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

Sin embargo, estos mensajes de blog por Gavin Pugh mencionan comportamientos compatibles con el proceso de 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/

Además, la fuente de StringBuilder revelada por el reflector, y los comentarios adjuntos en el SSCLI fuente, también sugieren muchas consideraciones de implementación para garantizar la seguridad del hilo:

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

¿Alguien tiene más información sobre si una instancia de StringBuilder es segura para compartir entre múltiples subprocesos concurrentes?

Respuesta

21
Por supuesto que no

; He aquí un ejemplo sencillo levantado de 4.0 a través del 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; 
} 

El atributo solo se ocupa de las personas que llaman, no subprocesos de seguridad; esto es absolutamente no seguro para subprocesos.

Actualización: mirando la fuente a la que hace referencia, esta no es claramente la base de código .NET 4.0 actual (comparando algunos métodos). Tal vez él está hablando de una versión .NET particular, o tal vez XNA - pero es no el caso en general. El 4.0 StringBuilder no tiene tiene un campo m_currentThread, que utiliza el material de origen de Gavin; hay una pista (una constante no utilizada ThreadIDField) que usó para existir, pero ... ya no.


Si desea una refutación directa- ejecutar esto en 4.0; probablemente dará la longitud incorrecta (he visto algunos en la región 4k, algunos en la región 2k - debería ser exactamente 5000), pero algunos otros métodos Append (Append(char) por ejemplo) tienden a arrojar excepciones , dependiendo del momento:

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

'String.Builder' hasta 3.5 todavía contiene el código de comprobación de hilo. Ver http://stackoverflow.com/a/3564934/3205 para más detalles. – skolima

5

El objetivo de la documentación es brindarle garantías. En este caso, en los miembros de la instancia no se garantiza que nada sea seguro para subprocesos y debe tratarlo como tal, por lo tanto, debe confiar en los métodos de sincronización externos.

que algunas cosas pueden ser multi-hilo es un detalle aplicación que puede y tal vez no cambiar de una versión del marco a otro o de una aplicación a otra (de hecho, hay un montón de detalles tan cambiante en las versiones marco, Eric Lippert tiene algunas publicaciones que detallan algunas de ellas). No confíes en eso

(En otras palabras:. No escribir código para una implementación, escribirlo en contra de la interfaz y el contrato que son los metadatos de la clase y su documentación en este caso)

0

Desde el MSDN documentation:

estáticos públicos (Shared en Visual Basic) de este tipo son seguros para subprocesos . No se garantiza que ningún miembro de la instancia sea seguro .