Ich muss einen Property-Getter von einer API eines Drittanbieters verwenden, und wenn ich nur auf diesen Getter zugreife manchmal hängt die gesamte Anwendung, manchmal funktioniert (in dev / debugger) . Und wenn ich es auf einem Produktionsserver bereitstellen, funktioniert die Host-Anwendung manchmal wie erwartet, manchmal stirbt mit einem APPCRASH in KERNEL32.
Ich konnte nicht verstehen, wie ein simpler Getter einfrieren oder irgendetwas abstürzen könnte, also dachte ich, dass diese Eigenschaft eine verkappte Methode war, und benutzte meinen Lieblings-Decompiler, um das herauszufinden.
Dies ist das Schema / Muster, auf das ich gestoßen bin:
%Vor% Bin ich richtig zu glauben, dass, wenn _myProperty
null
ist, der Getter den Setter aufruft und es hier einen Race Condition Bug gibt, der das zufällige / gelegentliche Einfrieren verursachen kann ? Wie kann ich bestätigen, dass dieses Einfrieren tatsächlich ein Deadlock ist?
Was wäre eine korrekte Implementierung? Ich bin der Überzeugung, dass, wenn der Setter auch ein lock (Locker)
hätte (ich mag auch nicht, dass Locker
öffentlich zugänglich ist, klingt nach Ärger), und der Getter würde _myProperty
zuweisen, anstatt den Setter, es wäre thread-safe.
Schließlich, gibt es eine Möglichkeit, wie ich diesen Getter nennen kann, ohne dass die dritte Partei eine "fixe" Version und ohne Einfrieren versenden muss?
Ich habe versucht, es aus dem Haupt-UIhread aufzurufen, ich habe versucht, es aus einem Task
/ background thread aufzurufen, ich habe vor dem Aufruf eine Sleep(200)
ausprobiert, ich habe versucht, ein Timeout für Task
zu setzen ... egal was ich tue, ich kann den Getter nicht konsistent nennen und das erwartete Ergebnis zuverlässig erhalten (es funktioniert manchmal ...).
Das Locker
-Objekt ist öffentlich, aber es ist in einem internal class
definiert, auf das ich nur über seine Schnittstelle zugreife, was es natürlich nicht aussetzt. Gibt es eine Möglichkeit, Reflektionen zu verwenden, um die Sperre von außen zu erhalten ( Monitor.TryEnter(magicallyObtainedLocker)
) und sie tatsächlich zum Laufen zu bringen? Oder ist dieser Getter vollständig borked ?
Bin ich richtig zu glauben, dass, wenn _myProperty null ist, der Getter den Setter aufruft und es hier einen Race Condition Bug gibt, der das zufällige / gelegentliche Einfrieren verursachen kann? Wie kann ich bestätigen, dass dieses Einfrieren tatsächlich ein Deadlock ist?
Nein. In C # ist lock
für denselben Thread wiedereintrittsfähig. Sie können dies in der Dokumentation für Monitor.Enter sehen:
Es ist legal, dass derselbe Thread mehrmals Enter aufruft, ohne dass er blockiert; Es muss jedoch eine gleiche Anzahl von Exit-Aufrufen aufgerufen werden, bevor andere Threads, die auf das Objekt warten, entsperrt werden.
mag nicht, dass der Locker auch öffentlich zugänglich ist, klingt nach Ärger zu fragen
Ich stimme dir hier zu. Dies ist eher der Schuldige. Die Tatsache, dass Locker
öffentlich ist, bedeutet höchstwahrscheinlich, dass etwas anderes in der Bibliothek dieses Objekt blockiert, was die Ursache des Deadlocks sein könnte.
Wenn Sie dies über den Visual Studio Concurrency Profiler ausführen können, sollten Sie in der Lage sein, den Deadlock anzuhalten und die Objekte zu diesem Zeitpunkt zu blockieren.
Gibt es eine Möglichkeit, Reflektion zu verwenden, um das Schloss von außen zu erhalten (Monitor.TryEnter (magicallyObtainedLocker)) und es tatsächlich zum Laufen zu bringen?
Ja, vorausgesetzt, dass Sie es dekompilieren könnten, würde ich so raten 1 ; das folgende ' funktioniert auf meinem Computer ' :
1 Ich nehme an, Sie können das Schloss von außen bekommen; und hoffen, aber nicht vorhersagen, ob das ausreichen wird, um den Stillstand zu vermeiden.
%Vor% %Vor%Tags und Links c# multithreading race-condition locking