valida uso una tuvo traves thread subprocesos subproceso sirve que para operacion net llamó interfaz form false diferente control checkforillegalcrossthreadcalls aplicación aplanó acceso c# multithreading logging thread-safety

uso - thread invoke c#



Implementación segura de la clase de registro de subprocesos (5)

¿Sería la siguiente la forma correcta de implementar una clase de registro de seguridad de subprocesos bastante sencilla?

Sé que nunca cierro explícitamente el TextWriter , ¿sería un problema?

Cuando utilicé inicialmente el método TextWriter.Synchronized , no pareció funcionar hasta que lo inicialicé en un constructor estático y lo hice de esta forma:

public static class Logger { static readonly TextWriter tw; static Logger() { tw = TextWriter.Synchronized(File.AppendText(SPath() + "//Log.txt")); } public static string SPath() { return ConfigManager.GetAppSetting("logPath"); } public static void Write(string logMessage) { try { Log(logMessage, tw); } catch (IOException e) { tw.Close(); } } public static void Log(string logMessage, TextWriter w) { w.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(), DateTime.Now.ToLongDateString()); w.WriteLine(" :"); w.WriteLine(" :{0}", logMessage); w.WriteLine("-------------------------------"); // Update the underlying file. w.Flush(); } }


Al llamar a TextWriter.Synchronized protegerá esa única instancia de TextWriter , no sincronizará sus escrituras para que una llamada de "Log" permanezca unida dentro del archivo.

Si llama a Write (o Log utilizando la instancia interna de TextWriter ) desde varios hilos, las llamadas individuales de WriteLine pueden entrelazarse, haciendo que sus sellos de fecha y hora no se puedan utilizar.

Yo personalmente usaría una solución de registro de terceros que ya existe para esto. Si eso no es una opción, sincronizar esto usted mismo (incluso con un simple bloqueo) probablemente sea más útil que usar el contenedor TextWriter.Synchronized del marco.


Alguien me señaló este post mientras discutía algunos problemas de registro hoy. Ya tenemos buenas respuestas aquí, pero estoy agregando mi respuesta solo para mostrar una versión más simple de la clase Logger que hace exactamente lo mismo, en una forma completamente Threadsafe para Threadsafe .
Una cosa importante a tener en cuenta aquí es que no se requiere TextWriter.Synchronized para la seguridad de subprocesos, ya que estamos escribiendo el archivo dentro de un lock adecuado.

Nota: Esto ya se ha discutido en la sección de comentarios de la respuesta de x0n.

public static class Logger { static readonly object _locker = new object(); public static void Log(string logMessage) { try { var logFilePath = Path.Combine(@"C:/YourLogDirectoryHere", "Log.txt"); //Use this for daily log files : "Log" + DateTime.Now.ToString("yyyy-MM-dd") + ".txt"; WriteToLog(logMessage, logFilePath); } catch (Exception e) { //log log-exception somewhere else if required! } } static void WriteToLog(string logMessage, string logFilePath) { lock (_locker) { File.AppendAllText(logFilePath, string.Format("Logged on: {1} at: {2}{0}Message: {3}{0}--------------------{0}", Environment.NewLine, DateTime.Now.ToLongDateString(), DateTime.Now.ToLongTimeString(), logMessage)); } } }

Para registrar algo, simplemente llame al

Logger.Log("Some important event has occurred!");

Y hará una entrada de registro como esta

Conectado: 07 de octubre de 2015 a las: 02:11:23
Mensaje: ¡Ha ocurrido algún evento importante!
--------------------


Debería ver esta clase (parte de .NET 2.0), no es necesario "crear" su propio registrador. le permite iniciar sesión en un archivo de texto, vista de evento, etc.

http://msdn.microsoft.com/en-us/library/system.diagnostics.tracesource.aspx

Su método "Log" puede verse más o menos así (suponiendo que exista una variable interna llamada ''traceSource''):

public void Log(TraceEventType eventType, string message) { this.traceSource.TraceEvent(eventType, 0, message); this.traceSource.Flush(); }

Esto es una sección de configuración que nombra TraceSource y tiene algunas configuraciones. Se supone que cuando construyes un TraceSource en tu registrador estás instanciando con una de las fuentes de rastreo nombradas en la configuración.

<system.diagnostics> <sources> <source name="Sample" switchValue="Information,ActivityTracing"> <listeners> <add name="file" initializeData="C:/temp/Sample-trace.log" traceOutputOptions="DateTime" type="System.Diagnostics.TextWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/> </listeners> </source> </sources>

Además, no pongas tu registrador estático. En su lugar, use Enterprise Library 5.0 Unity para Dependency Injection / IOC.

¡Espero que esto ayude!



Voy a tomar un enfoque completamente diferente aquí que las otras respuestas y supongo que realmente quieres aprender a escribir un mejor código de detección de subprocesos, y no estamos buscando sugerencias de terceros de parte nuestra (aunque en realidad puedas terminar usando uno.)

Como han dicho otros, está creando un TextWriter seguro para TextWriter que significa que las llamadas a WriteLine son seguras para subprocesos, eso no significa que se realizarán WriteLine llamadas a WriteLine como una operación atómica. Con eso quiero decir que no hay garantía de que las cuatro llamadas WriteLine vayan a suceder en secuencia. Puede tener un TextWriter seguro para TextWriter , pero no tiene un método Logger.Log seguro para Logger.Log ;) ¿Por qué? Porque en cualquier momento durante esas cuatro llamadas, otro hilo podría decidir llamar Log también. Esto significa que sus llamadas WriteLine no estarán sincronizadas. La forma de solucionar esto es usar una declaración de lock como esta:

private static readonly object _syncObject = new object(); public static void Log(string logMessage, TextWriter w) { // only one thread can own this lock, so other threads // entering this method will wait here until lock is // available. lock(_syncObject) { w.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(), DateTime.Now.ToLongDateString()); w.WriteLine(" :"); w.WriteLine(" :{0}", logMessage); w.WriteLine("-------------------------------"); // Update the underlying file. w.Flush(); } }

Entonces, ahora tienes un TextWriter seguro para TextWriter Y un TextWriter seguro TextWriter subprocesos.

¿Tener sentido?