Es gibt einen Teil des Codes, der Daten in ein MemoryStream-Objekt direkt in dessen Datenpuffer schreibt, indem er GetBuffer() aufruft. Er verwendet und aktualisiert auch die Eigenschaften Position und SetLength() entsprechend.
Dieser Code funktioniert in 99,9999 % der Fälle richtig. Buchstäblich. Nur alle 100.000 Iterationen wird er kotzen. Das spezifische Problem ist, dass die Position-Eigenschaft von MemoryStream plötzlich Null anstelle des entsprechenden Wertes zurückgibt.
Es wurde jedoch Code hinzugefügt, der auf die 0 prüft und eine Ausnahme auslöst, die ein Protokoll der MemoryStream-Eigenschaften wie Position und Länge in einer separaten Methode enthält. Diese geben den richtigen Wert zurück. Eine weitere Ergänzung der Protokollierung innerhalb derselben Methode zeigt, dass in diesem seltenen Fall die Position nur innerhalb dieser speziellen Methode Null ist.
Ja. Offensichtlich muss es sich um ein Threading-Problem handeln. Und höchstwahrscheinlich ein Compiler-Optimierungsproblem.
Es liegt jedoch in der Natur dieser Software, dass sie nach "Tasks" mit einem Scheduler organisiert ist, so dass ein beliebiger von mehreren tatsächlichen Betriebssystem-Threads diesen Code zu einem beliebigen Zeitpunkt ausführen kann - aber niemals mehr als einer gleichzeitig.
Ich vermute also, dass es normalerweise so ist, dass immer derselbe Faden für diese Methode verwendet wird und dann bei einer seltenen Gelegenheit ein anderer. (Ich habe gerade die Idee, diese Theorie zu testen, indem ich die Thread-ID erfasse und vergleiche).
Aufgrund von Compiler-Optimierungen erhält der andere Thread dann nie den richtigen Wert. Er erhält einen "veralteten" Wert.
Normalerweise würde ich in einer Situation wie dieser ein "volatile"-Schlüsselwort auf die betreffende Variable anwenden, um zu sehen, ob das Problem dadurch behoben wird. Aber in diesem Fall befinden sich die Variablen innerhalb des MemoryStream-Objekts.
Hat jemand eine andere Idee? Oder bedeutet dies, dass wir unser eigenes MemoryStream-Objekt implementieren müssen?
Mit freundlichen Grüßen, Wayne
EDIT: Ich habe gerade einen Test durchgeführt, der die Gesamtzahl der Aufrufe dieser Methode zählt und die Anzahl der Male zählt, in denen sich die ManagedThreadId vom letzten Aufruf unterscheidet. Es ist fast genau 50% der Zeit, dass es schaltet Threads - abwechselnd zwischen ihnen. Meine obige Theorie ist also mit ziemlicher Sicherheit falsch, sonst würde der Fehler viel häufiger auftreten.
EDIT: T
EDIT: Sperren wird derzeit über lock()-Anweisungen in jeder der 5 Methoden, die den MemoryStream verwenden, behandelt.