Gleichzeitige XmlReader und XmlWriter

8

Ich habe ein System, das einige XmlReader und XmlWriter Instanzen erstellt, und übergibt sie Clients , so dass die Clients XML schreiben und lesen können.

Manchmal greifen mehrere Threads auf das System zu:

  1. Thread 1 erhält eine XmlWriter Instanz und beginnt mit dem Schreiben
  2. Thread 2 ruft eine XmlReader -Instanz ab, die dasselbe XML-Dokument darstellt, und beginnt mit dem Lesen.

Offensichtlich beginnt der Leser manchmal zu lesen, bevor der Schreiber den Schreibvorgang abgeschlossen hat, wodurch eine Ausnahme im Leser ausgelöst wird:

  

System.Xml.XmlException: Root-Element fehlt.

Das ist nicht besonders überraschend, aber gibt es eine Möglichkeit, dieses System threadsicher zu machen?

  • Ist es möglich, dass der Leser liest, während der Writer schreibt? Ich habe versucht, einen MemoryStream als zugrunde liegenden Datenspeicher zu verwenden, aber das schien nicht zu funktionieren.
  • Ist es möglich, den Leser warten zu lassen, bis der Schreiber fertig geschrieben hat?
  • Ist es möglich zu erkennen, dass der Schreiber noch schreibt?

Jeder der obigen Ansätze würde meines Erachtens mein Problem lösen. Es ist nicht erforderlich, dass das Schreiben und Lesen gleichzeitig erfolgt. Eigentlich wäre ich sehr glücklich, wenn ich dem Kunden einfach mitteilen könnte, dass der Reader noch nicht bereit ist, und es später erneut versuchen muss. Dies erfordert jedoch, dass es eine Möglichkeit gibt zu erkennen, dass der Schreiber noch schreibt.

Ich habe die volle Kontrolle über den Code, der die Instanzen XmlReader und XmlReader erstellt, aber ich kann die öffentliche API nicht ändern. Ich kann ein XmlWriter , ein string , ein StringBuilder oder irgendein anderes speicherinternes Objekt, das den Job erledigt, als zugrunde liegenden Speicher verwenden, und ich kann jede abgeleitete Klasse von MemoryStream und% co_de verwenden %.

Gibt es eine Möglichkeit, dieses System threadsicher zu machen?

    
Mark Seemann 24.04.2014, 18:10
quelle

6 Antworten

7

Am besten ist es wahrscheinlich, benutzerdefinierte Klassen zu erstellen, die von XmlReader und XmlWriter abgeleitet sind. Sie können ihnen ein gemeinsames Synchronisationsobjekt hinzufügen und so etwas wie ReadWriterLockSlim zum Koordinieren von Lesen und Schreiben verwenden. Sie müssten in der Writerklasse bestimmen, was Sie meinen, wenn Sie sagen, es sei "erledigt" (erledigt? Schreiben eines einzelnen Knotens, auch wenn es nicht komplett fertig ist? Usw.)

Sie können dann einfach die Methoden im Leseblock machen, bis das Schreiben nicht mehr läuft.

    
Adam Robinson 24.04.2014, 18:14
quelle
3

Sie suchen nach einem Stream, mit dem ein Thread schreiben kann, während der andere liest. Das .NET Framework liefert so etwas nicht. Sie könnten es möglicherweise mit einer Named Pipe tun, aber ich fand das umständlich. Also schrieb ich, was ich ProducerConsumerStream nannte. Es ist nur eine zirkuläre Warteschlange in einer Stream -Schnittstelle. Siehe Erstellen eines neuen Stream-Typs für eine Beschreibung und eine vollständige Quelle.

Um es mit XmlWriter und XmlReader zu verwenden, tun Sie etwas wie folgt:

%Vor%

Der Producer-Thread würde ein XmlWriter erstellen, das in den Stream schreibt:

%Vor%

Der Leser-Thread ist ähnlich:

%Vor%

Achten Sie darauf, dass Sie in Ihren Schreibereinstellungen CloseOutput = false und in den Lesereinstellungen CloseInput = false festgelegt haben. Andernfalls könnte der Stream vorzeitig entsorgt werden.

Der Schlüssel hier ist, dass ProducerConsumerStream.Read blockiert, bis es Daten lesen kann. Es sei denn, das Ende des Streams wurde durch Aufruf von CompleteAdding signalisiert.

Verstehen Sie, das ist eine In-Memory-Struktur. Wenn Sie auch den XML-Code beibehalten möchten, müssen Sie dies auf andere Weise tun. Ich nehme an, Sie könnten von ProducerConsumerStream ableiten und die Methode Write überschreiben, so dass sie sowohl in die Datei als auch in den internen Puffer kopiert wird.

    
Jim Mischel 24.04.2014 19:22
quelle
2

Es klingt, als ob Sie etwas ähnliches wie PipedReader / PipedWriter in Java benötigen. Ссылка . Es sieht so aus, als hätte .NET nichts Vergleichbares: Javas PipedReader / PipedWriter-Entsprechungen in C # ? .

Sie können dasselbe wie in Java tun, indem Sie Ihren eigenen System.IO.TextWriter und System.IO.TextReader implementieren, indem Sie diesen Java-Code als Basis verwenden:

Ссылка

Ссылка

    
Juan-Carlos 24.04.2014 18:37
quelle
2
  

Ist es möglich, den Leser warten zu lassen, bis der Schreiber das Schreiben abgeschlossen hat?

Ja mit einem Hybrid-Thread-Synchronisationskonstrukt , z.B. ManualResetEventSlim wie folgt:

%Vor%

Konsolenausgabe:

%Vor%

Die Funktion CreateXmlDocument (obwohl sie nicht sehr interessant ist) ist definiert als:

%Vor%     
Nikos Baxevanis 24.04.2014 20:53
quelle
0

Eine einfache Idee besteht darin, ein (möglicherweise statisches) Wörterbuch von Dokumenten zu erstellen, die gerade geschrieben werden. Während sich das Dokument in diesem Wörterbuch befindet, werden Leseanforderungen entweder blockiert oder zurückgewiesen.

    
T McKeown 24.04.2014 18:14
quelle
-2

Gute Idee ist es, eine Kopie der XML-Datei in einer Sperre zu erstellen, die sich auch auf einen XMLWriter auswirkt.

Writer-Code:

%Vor%

Lesercode:

%Vor%     
tas 24.04.2014 18:16
quelle

Tags und Links