Ausnahme beim Hinzufügen eines Wörterbucheintrags

8

Diese Ausnahme tritt im folgenden Codeblock in einem ASP.NET-Kontext auf, der auf einem IIS 7-Server ausgeführt wird.

%Vor%

Dies ist der Code, in dem die Ausnahme auftritt:

%Vor%

Der Monitor.TryEnter sollte verhindern, dass mehrere Threads gleichzeitig in den Block gelangen, und der Code überprüft das Dictionary, um sicherzustellen, dass er den hinzuzufügenden Schlüssel nicht enthält.

Irgendwelche Ideen, wie das passieren könnte?

    
Avalanchis 16.11.2011, 11:49
quelle

3 Antworten

5

Ihr Code ist nicht threadsicher.

  1. Sie sperren this , eine CredentialsSession -Instanz, greifen aber auf ein statisches Verzeichnis zu, das von mehreren CredentialsSession -Instanzen gemeinsam genutzt werden kann. Dies erklärt, warum Sie den Fehler erhalten - zwei verschiedene CredentialsSession Instanzen versuchen gleichzeitig in das Wörterbuch zu schreiben.

  2. Auch wenn Sie dies so ändern, dass ein statisches Feld gesperrt wird, wie in @ slls Antwort vorgeschlagen, sind Sie nicht Thread-sicher, weil Sie beim Lesen des Wörterbuchs nicht sperren. Sie benötigen ReaderWriterLock oder ReaderWriterLockSlim , um mehrere Leser und einen einzelnen Schreiber effizient zuzulassen.

    Daher sollten Sie wahrscheinlich ein thread-sicheres Wörterbuch verwenden. ConcurrentDictionary , wie andere gesagt haben, wenn Sie .NET 4.0 verwenden. Wenn nicht, sollten Sie Ihre eigenen implementieren oder eine vorhandene Implementierung wie Ссылка .

Ihre Kommentare legen nahe, dass Sie vermeiden möchten, dass CreateSerializer mehrmals für denselben Typ aufgerufen wird. Ich weiß nicht, warum, weil der Leistungsvorteil wahrscheinlich vernachlässigbar ist, da die Konkurrenz wahrscheinlich selten ist und während der Lebensdauer der Anwendung nicht für jeden Typ einmal überschreiten darf.

Aber wenn Sie das wirklich wollen, können Sie es wie folgt machen:

%Vor%

Vom Kommentar:

  

, wenn ich dies mit ConcurrentDictionary implementiere und TryAdd (sessionObjectName, CreateSerializer (serializerType)) jedes Mal aufruft.

Die Antwort besteht nicht darin, TryAdd jedes Mal aufzurufen - prüfen Sie zuerst, ob es sich im Wörterbuch befindet, und fügen Sie es hinzu, wenn dies nicht der Fall ist. Eine bessere Alternative könnte sein, die GetOrAdd Überladung zu verwenden, die ein Argument Func benötigt.

    
Joe 16.11.2011, 12:32
quelle
5

Probieren Sie die Sperre für localSerializers statt für this aus. BTW, warum verwenden Sie Monitor explizit? Nur ein Grund, den ich sehe, ist Sperr-Timeout , das Sie offensichtlich nicht verwenden, also verwenden Sie einfach lock () statement stattdessen würde dies try / finally as generieren gut:

%Vor%

BEARBEITEN: Da Sie keine Tags angegeben haben, die .NET 4 verwenden, würde ich vorschlagen, sie zu verwenden ConcurrentDictionary<TKey, TValue>

Monitor.Enter () -Methode :

  

Benutze ein C # versuchen ... endlich Blockieren (Versuch ... Endlich in Visual Basic) um sicherzustellen   dass Sie den Monitor freigeben oder die C # lock -Anweisung (SyncLock   Anweisung in Visual Basic), die die Methoden Enter und Exit umschließt   ein Versuch ... endlich blockieren

    
sll 16.11.2011 11:53
quelle
1

Wenn Sie mit .NET Framework 4 oder höher arbeiten, würde ich vorschlagen, dass Sie ein ConcurrentDictionary verwenden. stattdessen. Die TryAdd -Methode schützt Sie vor dieser Art von Szenario, ohne dass Sie Ihren Code mit Sperren versehen müssen:

%Vor%

Wenn Sie sich Sorgen machen, dass CreateSerializer aufgerufen werden soll, wenn es nicht benötigt wird, sollten Sie stattdessen AddOrUpdate :

verwenden %Vor%

Dadurch wird sichergestellt, dass die Methode nur aufgerufen wird, wenn Sie einen neuen Wert erstellen müssen (wenn sie dem Wörterbuch hinzugefügt werden muss). Wenn es bereits vorhanden ist, wird der Eintrag mit dem bereits vorhandenen Wert "aktualisiert".

    
Fredrik Mörk 16.11.2011 11:57
quelle