Gibt es eine Möglichkeit, wie ich diesen Getter aufrufen kann und immer das erwartete Ergebnis bekomme?

8

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 ?

    
Mathieu Guindon 31.01.2014, 20:06
quelle

2 Antworten

5
  

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.

    
Reed Copsey 31.01.2014 20:09
quelle
2
  

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 ' :

  • "ThirdParty" ist in einem eigenen, separaten Projekt als DLL
  • aufgebaut
  • "InternalLocker" ist ein Konsolenprogramm in einem anderen Projekt, das auf die ThirdParty-DLL
  • verweist

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%     
ChrisW 31.01.2014 21:14
quelle