Ich bin nicht sicher, ob ich etwas hinzufügen kann, was bereits gesagt wurde, um eine Protokollierungsklasse threadsicher zu machen. Wie bereits erwähnt, müssen Sie dazu den Zugriff auf die Ressource, d. H. Die Protokolldatei, synchronisieren, so dass nur ein Thread versucht, sich gleichzeitig an der Ressource anzumelden. Das C# lock
-Schlüsselwort ist der richtige Weg, dies zu tun.
Ich werde jedoch (1) die Singleton-Ansatz und (2) die Benutzerfreundlichkeit des Ansatzes, die Sie letztlich entscheiden, zu verwenden.
(1) Wenn Ihre Anwendung alle Protokollmeldungen in eine einzige Protokolldatei schreibt, ist das Singleton-Muster definitiv die Route, die es zu gehen gilt. Die Protokolldatei wird beim Start geöffnet und beim Herunterfahren geschlossen, und das Singleton-Muster passt perfekt zu diesem Betriebskonzept. Wie @ dtb schon sagte, erinnern Sie sich daran, dass das Gewährleisten einer Singleton-Klasse die Thread-Sicherheit nicht garantiert. Verwenden Sie dafür das Schlüsselwort lock
.
(2) Was die Brauchbarkeit des Ansatzes betrachten diese vorgeschlagene Lösung:
public class SharedLogger : ILogger
{
public static SharedLogger Instance = new SharedLogger();
public void Write(string s)
{
lock (_lock)
{
_writer.Write(s);
}
}
private SharedLogger()
{
_writer = new LogWriter();
}
private object _lock;
private LogWriter _writer;
}
Lassen Sie mich zunächst sagen, dass dieser Ansatz im Allgemeinen in Ordnung ist. Es definiert eine Singleton-Instanz von SharedLogger
über die statische Variable Instance
und verhindert, dass andere die Klasse aufgrund des privaten Konstruktors instanziieren. Dies ist die Essenz des Singleton-Musters, aber ich empfehle dringend, Jon Skeets Rat bezüglich singletons in C# zu lesen und zu befolgen, bevor Sie zu weit gehen.
Allerdings möchte ich auf die Benutzerfreundlichkeit dieser Lösung konzentrieren. Mit "Usability" beziehe ich mich darauf, wie man diese Implementierung verwenden würde, um eine Nachricht zu protokollieren. Überlegen Sie, was der Aufruf wie folgt aussieht:
SharedLogger.Instance.Write("log message");
Das ganze ‚Instanz‘ Teil sieht einfach falsch, aber es gibt keine Möglichkeit sie die Umsetzung gegeben zu vermeiden. Stattdessen betrachten diese Alternative:
public static class SharedLogger : ILogger
{
private static LogWriter _writer = new LogWriter();
private static object _lock = new object();
public static void Write(string s)
{
lock (_lock)
{
_writer.Write(s);
}
}
}
Beachten Sie, dass die Klasse jetzt statisch ist, was bedeutet, dass alle ihre Mitglieder und Methoden statisch sein. Es unterscheidet sich nicht wesentlich von dem vorherigen Beispiel, aber beachte seine Verwendung.
SharedLogger.Write("log message");
Das ist viel einfacher zu codieren.
Es geht nicht darum, die frühere Lösung zu verunglimpfen, sondern zu empfehlen, dass die Verwendbarkeit der von Ihnen gewählten Lösung ein wichtiger Aspekt ist, der nicht zu übersehen ist. Eine gute, verwendbare API kann den Code einfacher schreiben, eleganter und einfacher zu verwalten.
Das Singleton-Muster impliziert keine Thread-Sicherheit. – dtb
Beginnen Sie damit, sorgfältig zu definieren, was Sie mit "thread safe" meinen. Die Leute benutzen diesen Begriff so, als ob er etwas Spezifisches bedeutet, obwohl es in Wirklichkeit bedeutet, dass es "in Szenario X korrekt funktioniert". Ohne eine Spezifikation für "richtig" und eine Aussage darüber, was X ist, kannst du nicht wirklich etwas implementieren und wissen, dass du ein Problem gelöst hast, das du wirklich hast. –
Schauen Sie sich [diesen tollen Artikel] (http://www.albahari.com/threading/part2.aspx#_ThreadSafety) von Joseph Albahari an. Etwa halb in den Artikel ist ein großer Abschnitt über "Thread Safety" –