Frage

Was ist der beste Weg, um ein Programm zu erstellen, die die Threadsicherheit in Bezug auf ist, dass es doppelte Werte in eine Datei schreiben muss. Wenn die Funktion, die die Werte über Stream speichert wird von mehreren Threads aufgerufen? Was ist der beste Weg, es zu tun?


-Code von Kommentar:

    static void Main()
    {
        List<double> Values = new List<double>();
        StreamWriter writer = new StreamWriter("test.out");

        for (int i = 0; i < 1000; i++) Values.Add(i);

        foreach (double V in Values)
        {
            ThreadPool.QueueUserWorkItem(delegate(object state) { SaveValues(writer, V); }, V);
        }
    }

    static void SaveValues(StreamWriter writer, double Value)
    {
        lock (writer) writer.WriteLine(Value);
    } 
War es hilfreich?

Lösung

Bearbeiten, nach der Dekodierung des Codes in Ihrem Kommentar

Ihr Problem ist nicht mit Rast- oder Fäden, sondern mit der Schleifenvariable zu erfassen. Dies ist ein klassisches Problem, alle Threads laufen mit einem ‚capture‘ der einzelnen V variabel und durch die Zeit, die Fäden ausgeführt werden seinen endgültigen Wert von 999. Außer vielleicht für die ersten Arbeitsschritte erreicht.

Also, statt:

foreach (double V in Values)
{  
   ThreadPool.QueueUserWorkItem(delegate(object state) 
        { SaveValues(writer, V); }, V); // use of captured V: almost always 999
}

Verwendung

foreach (double V in Values)
{
    double W = V;
    ThreadPool.QueueUserWorkItem(delegate(object state)
       { SaveValues(writer, W); }, V);
}

oder, etwas prägnanter,

foreach (double V in Values)
{
    double W = V;
    ThreadPool.QueueUserWorkItem((state) => SaveValues(writer, W));
}

Als Variante @ Matti Antwort, ist es auf einem separaten einfaches Objekt zu Sperre empfohlen. Dies reduziert das Risiko von irgendetwas anderen Verriegelung auf demselben Objekt (der Stream Code selbst zum Beispiel).

private StreamWriter writer = ...;         
private Object writerLock = new Object();  // don't expose through a property 
// or any other way

lock (writerLock)
{
    writer.Write(...);
}

Aber die Art und Weise Sie die SaveValues(StreamWriter writer, ...) Methode eingerichtet haben machen es ein wenig komplizierter. Es ist besser, ein Objekt zu haben, wo writer und writerLock sind sowohl private Mitglieder.

Andere Tipps

TextWriter.Synchronized

Erstellt eine Thread-sichere Wrapper um den angegebenen Textwriter. ll Schreiben in die zurück Wrapper-Thread sicher sein.

Lock it, während es den Zugriff.

lock (myStreamWriter) {
    myStreamWriter.Write(...);
}

wird Das loszuwerden, das Problem von mehreren Threads zugreifen wollte es einmal. Natürlich, wenn Sie benötigen, um weiter, dass die Dinge sorgen in der richtigen Reihenfolge von mehreren Threads geschrieben werden Sie zusätzliche Logik hinzufügen müssen.

Normalerweise, wenn Ein- oder Ausgang zu tun, ziehe ich eine Erzeuger / Verbraucher-Warteschlange mit nur einem Verbraucher, der das eigentliche Schreiben der Ausgabe der Fall ist.

Sie können mit einer Sperre auf dem Stream (oder ein Synchronisationsobjekt, das verwendet wird, wenn Threads Zugriff auf die Stream will) synchronisieren. Wenn jedoch mehrere Threads zu schreiben versuchen, werden nur in der Lage sein, um fortzufahren.

Wenn dies ein Problem ist, können Sie stattdessen eine Warteschlange, implementieren und einen Writer-Thread hinzufügen. Der Autor Thread wird aus der Warteschlange entfernt, und auf die Streamwriter schreiben. Die anderen Threads werden Elemente einreihen statt Artikel direkt zu schreiben.

Sie haben irgendeine Form der Synchronisation für den Zugang haben zu dieser Warteschlange. Sie könnten einfach sperren, wenn jeder Thread auf sie zugreift. Wenn Sie nicht vorsichtig sind, könnte allerdings schaffen schlechtere Performance-Probleme, als Sie beginnen hatten.

Bearbeiten

Es sieht aus wie Stephen Cleary einen Link zu einer bestehenden .NET-Klasse hat man die Warteschlange implementieren kann. Ich werde meine Antwort hinterlassen, da es erklärt, warum Sie Erzeuger / Verbraucher tun wollen würde.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top