2013-06-15 5 views
7

Hier ist also mein benutzerdefiniertes Dienstprogramm für doppelt geprüftes Sperren: Es ist eine statische Methode, in die Sie das Kriterium, das Synchronisierungsobjekt und die auszuführende Aktion eingeben.Ist es möglich, einen Test zu erstellen, der das Fehlschlagen der doppelten Überprüfung in C# anzeigt?

public static bool RunIf(Func<bool> criterion, object syncObject, Action action) 
{ 
    if (criterion()) 
     lock(syncObject) 
      if (criterion()) 
      { 
       Thread.MemoryBarrier(); 
       action(); 
       return true; 
      } 
    return false; 
} 

Ich bin, das zu verstehen gegeben, nach der C# Spezifikation ist es möglich, für Optimisern Speicherzuordnungen in einer solchen Art und Weise neu zu ordnen, dass ohne die Speicherbarriere kann diese Technik ein falsch positives geben und führen die Aktion, wenn es nicht sollte. Wenn in meiner kleinen Welt ein solcher Fehler möglich ist, sollte es auch möglich sein, einen Test zu entwickeln, der den Fehler konsequent demonstriert, indem er das Szenario mit einer ausreichenden Anzahl paralleler Testfälle hart genug trifft. Ich bin seit ungefähr einem Jahr auf der Suche nach einem solchen Test, aber bis jetzt habe ich eine Lücke gezogen. Kann mir jemand einen Test zeigen, dass:

  1. zeigt den Ausfall dieser Methode in Abwesenheit der Speicherbarriere;

  2. zeigt seinen Erfolg, wenn der Test mit der wiederhergestellten Speicherbarriere wiederholt wird?

+3

Ich glaube, .NET Framework auf x86 hat stärker Speichermodell als was die C# -Spezifikation erfordert, so dass Sie nicht in der Lage, einen solchen Test zu erstellen. Möglicherweise haben Sie mehr Glück auf ARM (d. H. Windows RT), die ein schwächeres Speichermodell hat. – svick

+3

svick ist korrekt. Schauen Sie sich [diesen MSDN-Artikel] (http://msdn.microsoft.com/en-us/magazine/cc163715.aspx#S5) an, der über das stärkere Speichermodell für .Net 2+ spricht. –

Antwort

1

Nein, es ist nicht möglich, nicht-deterministisches Verhalten zu testen (oder zumindest, wenn Sie das tun, dann wird ein negatives Ergebnis ist noch nicht schlüssig).

+0

Zustimmen, man könnte mit einem Test kommen, um zwei Threads zum Aufruf der Methode zu bekommen. Sie können jedoch nicht deterministisch zwischen den beiden Threads wechseln. Das implementierte Muster ist jedoch allgemein bekannt und es sollte ein einfacher Code-Review durchgeführt werden. –

+0

Das wirft eine andere Frage auf. Sie könnten tatsächlich die doppelt überprüfte Verriegelung vollständig abzweigen und ein einfältiges unsiches Singleton-Muster implementieren. Obwohl es keine Garantie dafür gibt, dass dies bei parallelen Threads fehlschlägt - dies ist, wie Sie sagen, nicht-deterministisches Verhalten -, wenn Sie es mit ein paar Millionen parallelen Threads treffen, sind die Chancen, dass es scheitern wird, so groß, dass es ist effektiv ein deterministischer Test. Wäre das eine schlechte Praxis? –

0

Es ist nicht möglich, einen solchen Test zu erstellen, da die Anweisung "lock" bereits einen vollständigen Fence (d. H. Einen Acquire- und Release-Fence) für den gesperrten Block von Anweisungen erstellt. Somit ist das zusätzliche Thread.MemoryBarrier() überflüssig und hat keine Auswirkung.

Also, je nachdem, was der übergebene Delegat criterion tut, ist Ihr RunIf Konstrukt entweder sicher oder völlig überflüssig.

Was ich damit meine, ist, dass, wenn der übergebene in criterion Delegierten ihren Rückgabewert von wandelbarem Zustand leitet, und dieser wandelbare Zustand nicht geschützt ist (entweder direkt oder indirekt) durch die gleichen syncObject, dieser Code nicht sicher ist und RunIf hat im Grunde keine Wirkung, außer um die Anweisungen zu umgeben, die in dem zweiten Anruf an die criterion Delegierten mit einem vollen Zaun durchgeführt werden.

Verwandte Themen