Synchroniser l’access au thread et écrire en C #

J’ai une application d’parsing de port multithread écrite en C # et je souhaite imprimer des éléments à la fois sur la console et sur un fichier journal pendant l’exécution de l’application. Pour cette raison, j’ai la classe d’aide suivante, qui fonctionne bien en écriture dans un fichier journal et dans la console.

public class Output { private const ssortingng LOG_DIRECTORY = "Logs"; private readonly ssortingng LogDirPath = Path.Combine(Directory.GetCurrentDirectory(), LOG_DIRECTORY); private static Output _outputSingleton; private static Output OutputSingleton { get { if (_outputSingleton == null) { _outputSingleton = new Output(); } return _outputSingleton; } } public StreamWriter SW { get; set; } public Output() { EnsureLogDirectoryExists(); InstantiateStreamWriter(); } ~Output() { if (SW != null) { try { SW.Dispose(); } catch (ObjectDisposedException) { } // object already disposed - ignore exception } } public static void WriteLine(ssortingng str) { Console.WriteLine(str); OutputSingleton.SW.WriteLine(str); } public static void Write(ssortingng str) { Console.Write(str); OutputSingleton.SW.Write(str); } private void InstantiateStreamWriter() { long ticks = DateTime.Now.Ticks; ssortingng logFilename = "scan_" + ticks.ToSsortingng() + ".txt"; ssortingng filePath = Path.Combine(LogDirPath, logFilename); try { SW = new StreamWriter(filePath); SW.AutoFlush = true; } catch (UnauthorizedAccessException ex) { throw new ApplicationException(ssortingng.Format("Access denied. Could not instantiate StreamWriter using path: {0}.", filePath), ex); } } private void EnsureLogDirectoryExists() { if (!Directory.Exists(LogDirPath)) { try { Directory.CreateDirectory(LogDirPath); } catch (UnauthorizedAccessException ex) { throw new ApplicationException(ssortingng.Format("Access denied. Could not create log directory using path: {0}.", LogDirPath), ex); } } } } 

Le problème est que, étant donné que mon application est multithreading, plusieurs fichiers journaux sont parfois créés, chacun partiellement écrit et une exception est parfois générée car un thread ne peut pas accéder au même emplacement pour être écrit lorsqu’il est utilisé par un autre thread. Existe-t-il un moyen de rendre multithread également ma classe de Output ci-dessus, afin d’éviter les problèmes susmentionnés?

Utiliser un seul fichier et une stratégie de lock devrait suffire:

 private Object m_Lock = new Object(); public static void WriteLine(ssortingng str) { lock (m_Lock) { Console.WriteLine(str); OutputSingleton.SW.WriteLine(str); } } public static void Write(ssortingng str) { lock (m_Lock) { Console.Write(str); OutputSingleton.SW.Write(str); } } private void InstantiateStreamWriter() { ssortingng logFilename = "Log.txt"; ssortingng filePath = Path.Combine(LogDirPath, logFilename); try { SW = new StreamWriter(filePath); SW.AutoFlush = true; } catch (UnauthorizedAccessException ex) { throw new ApplicationException(ssortingng.Format("Access denied. Could not instantiate StreamWriter using path: {0}.", filePath), ex); } } 

Le problème ici vient avec le verrou partagé. Si vous utilisez le même locking sur plusieurs méthodes, le locking d’une méthode verrouille également les autres méthodes (dans votre cas, Write et WriteLine ). Cela me semble tout à fait correct car ils sont ssortingctement liés … mais cela peut créer un goulot d’étranglement si les méthodes sont appelées très fréquemment. De l’autre côté, des verrous séparés permettraient aux méthodes d’être exécutées indépendamment, ce qui est encore pire.

Essayez de fusionner les deux méthodes en une comme suit, de sorte que vous n’ayez pas à vous soucier de la gestion des verrous sur des méthodes distinctes:

 public static void WriteLine(Ssortingng str, Boolean line = true) { lock (m_Lock) { if (line) { Console.WriteLine(str); OutputSingleton.SW.WriteLine(str); } else { Console.Write(str); OutputSingleton.SW.Write(str); } } }