2016-07-12 20 views
0

Ich habe eine Datei mit einem Basispfad zu allen meinen Ressourcen. Zum Beispiel:Wird Code eine Race Condition produzieren?

build/scripts/script1.js 
build/scripts/script2.js 

ich natürlich brauche einen Basispfad zum Beispiel:

https://example.org/SuperDuperSite/build/scripts/script1.js 

Was ich habe gehofft, dass die Datei in ein globales Wörterbuch mit dem Pfad beim Start zu tun war, zu laden. Das Wörterbuch müsste nur einmal geladen werden. Leider, soweit ich das beurteilen kann, ist der Basispfad erst bei der ersten Anfrage verfügbar. Also in asp.net muss ich application_beginrequest statt application_start verwenden. Was daran schlimm ist, ist jetzt, dass ich mich mit Multithreading-Problemen befassen muss.

, die mich zwingt, die folgende Art von Code zu schreiben:

lock(_lock) { 
    if (_dictionary == null) { 
     LoadDictionary(); 
    } 
    } 

Diese für jede einzelne Anforderung aufgerufen werden würde, wenn ich nur wirklich einmal brauchen zu laden. Das mag ich natürlich nicht. Ich möchte nicht jede einzelne Anforderung aus Leistungsgründen sperren müssen. Eine Lösung, die nach dem Gespräch mit Hochschulen, die wir kamen mit:

if (_dictionary == null) 
{ 
    lock(_lock) { 
     if (_dictionary == null) { 
     LoadDictionary(); 
     } 
    } 
} 

Also mit dieser Lösung würde ich nicht jede einzelne Anfrage zu erfassen erforderlich sein, aber wenn mehrere Threads am Ende immer diesen Abschnitt beim Start würde ich dann schützen Überprüfen Sie, ob das Objekt innerhalb der Sperre wieder null ist. Wird dieser Code funktionieren oder werde ich in einen Wettlauf geraten?

+0

Klingt wie eine Menge Komplexität, um eine Basis-URL aufzunehmen. Gibt es einen Grund, warum Sie beim Start den Pfad in ein Wörterbuch geladen haben? –

+1

Sind Sie sicher, dass Sie dies aus dem richtigen Winkel angreifen? Gibt es einen Grund, warum Sie keine relativen Pfadanforderungen ausführen können? –

+1

Doppelt überprüfte Verriegelung ist in C# sicher.Bedingungen im Codebeispiel sind rückwärts, aber andere in Ordnung. –

Antwort

1

Vorsicht bei der Verwendung von doppelt geprüften Schlössern.

Ja, es ist Thread-sicher, aber in Ihre speziellen Code Sie vielleicht in einen subtilen Fehler laufen, wo _dictionary von den anderen Thread instanziiert wurde (vorbei an der null Prüfung), aber nicht vollständig noch bevölkert und Sie versuchen möglicherweise, auf ein teilweise gefülltes Wörterbuch zuzugreifen. Und am Ende mit einer dieser beiden:

  1. Sie Ergebnisse fehlen, wenn das Wörterbuch zu lesen, oder noch schlimmer
  2. Es sei denn, Sie verwenden ein ConcurrentDictionary (die auch mit ihren Auswirkungen auf die Leistung kommt), können Sie sein Gleichzeitiges Lesen und Schreiben in das Wörterbuch und damit ein Deadlock (ja, die Klasse Dictionary verursacht bekanntermaßen in vielen Codes Deadlocks).

A bool _dictionaryLoaded Flag (doppelt überprüft), am Ende der LoadDictionary() zu true gekippt, ist wahrscheinlich besser.

Oder Lazy<> verwenden, wenn Sie .NET sind auf 4. Es ist viel sauberer, alles, was Sie tun müssen, ist Pass in LoadDictionary als init-Funktion verwendet werden.

Bearbeiten: Lazy <> ist internally implemented with a double-checked lock.