2011-01-26 15 views
10

Como un ejercicio de curiosidad más que nada, considere la siguiente clase simple de registro:.NET 2.0: File.AppendAllText (...) - Hilo de aplicación segura

internal static class Logging 
{ 
    private static object threadlock; 

    static Logging() 
    { 
     threadlock = new object(); 
    } 

    internal static void WriteLog(string message) 
    { 
     try 
     { 
      lock (threadlock) 
      { 
       File.AppendAllText(@"C:\logfile.log", message); 
      } 
     } 
     catch 
     { 
      ...handle logging errors... 
     } 
    } 
} 

¿Está la necesidad lock alrededor File.AppendAllText(...) o es el método intrínsecamente seguro para subprocesos mediante su propia implementación?

Buscando información sobre esto produce mucha información contradictoria, algunos dicen que sí, algunos dicen que no. MSDN no dice nada.

Respuesta

16

File.AppendAllText va a adquirir un bloqueo de escritura exclusivo en el archivo de registro, lo que haría que cualquier subproceso simultáneo que intente acceder al archivo genere una excepción. Así que sí, necesita un objeto de bloqueo estático para evitar que varios hilos intenten escribir en el archivo de registro al mismo tiempo y generar un IOException.

Si esto va a ser un problema, realmente sugeriría iniciar sesión en una tabla de base de datos que hará un mejor trabajo al manejar los escritores de registro simultáneos.

Alternativamente, puede usar TextWriterTraceListener que es seguro para subprocesos (bueno, va a hacer el bloqueo para usted, prefiero escribir lo menos posible de mi propio código multiproceso).

+1

Esto es contradictorio. Si File.AppendAllText tiene un bloqueo de escritura exclusivo, ¿por qué necesita un bloqueo por separado? – iheanyi

+4

No entendió, es el archivo que está bloqueado para escritura. Entonces, cualquier otro hilo que intente escribir al mismo tiempo recibirá una excepción. Para evitar eso, debe serializar las escrituras usando un bloqueo en su programa. – Pradeep

+0

no pierda su base de datos de recursos preciosos para el registro si está utilizando una base de datos relacional pesada de lo contrario si está utilizando una base de datos NoSQL Lite, entonces no es malo para iniciar la sesión en la base de datos. Use algo como el registro de eventos de Windows si desea iniciar sesión localmente, pero no escriba en el sistema de archivos usted mismo. Pero ¿por qué no escribir un nuevo archivo por registro en lugar de agregar si necesita ser seguro y no bloquear? –

0

Es seguro para subprocesos en el sentido de que abre el archivo con el uso compartido de Lectura, por lo que suponiendo que su sistema de archivos respeta los bloqueos de archivos, solo un subproceso tendrá permiso para escribir en el archivo a la vez. Sin embargo, otros subprocesos pueden leer sucios si intentan leer el mismo archivo.

+7

Y otros hilos arrojarán excepciones cuando intenten escribir. –

0

La prueba de escrituras paralelas muestra que obtendría una excepción System.IO.IOException si tuviera que comentar la instrucción de bloqueo.

[Test] 
public void Answer_Question() 
{ 
    var ex = Assert.Throws<AggregateException>(() => Parallel.Invoke(
     () => Logging.WriteLog("abc"), 
     () => Logging.WriteLog("123") 
    )); 

    // System.IO.IOException: The process cannot access the file 'C:\Logs\thread-safety-test.txt' because it is being used by another process. 
    Console.Write(ex); 
} 
Cuestiones relacionadas