2013-06-07 5 views
6

Ich habe mehrere Warteschlangen, auf die mehrere Threads zugreifen. Um Thread-Sicherheit zu erreichen, habe ich folgendes:Kann ich Wörterbuchelemente als Sperrobjekte verwenden?

private static Dictionary<string, Queue<string>> MyQueues = new Dictionary<string, Queue<string>>(); 

public static string GetNextQueueElementForKey(string key) 
{ 
    string res = string.Empty; 

    if (MyQueues.Keys.Contains(key)) 
    { 
     Queue<string> queue = MyQueues[key]; 
     lock (queue) 
     { 
      if (queue.Count() > 0) 
      { 
       res = queue.Dequeue(); 
      } 
     } 
    } 

    return res; 
} 

Ich könnte auch MyQueues sperren, aber dann würde ich sperren mehr als nötig. Meine Frage ist also, ob das Sperren eines in einem Wörterbuch enthaltenen Objekts funktioniert - vorausgesetzt, der Wert eines Schlüssels (die Warteschlange) wird nie geändert.

+0

Ihre Frage liest sich eher wie eine Aussage. Was ist wieder deine Frage? –

+0

Sie sperren keine Objekte, Sie sperren * Verweise auf Objekte *. Mit anderen Worten, ob sich der Wert des Objekts ändert, hat keinen Einfluss auf die Sperre. – Nolonar

+0

@Nolonar nein, Sie sperren das Objekt selbst. Du könntest 17 Referenzen auf das gleiche Objekt haben - sie würden alle dasselbe sperren. –

Antwort

6

Sie kann - aber ich im Allgemeinen würde nicht. Persönlich versuche ich normalerweise, einfache System.Object Instanzen zu sperren, die für nichts anderes verwendet werden, und im Idealfall sind sie keinem anderen Code als der Klassensperrung für sie ausgesetzt. Auf diese Weise können Sie absolut sicher sein, dass nichts anderes gesperrt wird.

In diesem Fall sieht es aus wie Sie die Kontrolle über die Warteschlangen haben, so dass Sie wissen, dass sie nicht von anderem Code verwendet werden, aber es ist möglich , dass der Code innerhalb Queue<T> auf this sperren wird. Das ist wahrscheinlich nicht der Fall, aber ich mache mir solche Sorgen.

Grundsätzlich wünschte ich, dass .NET nicht Java Ansatz von "ein Monitor für jedes Objekt" genommen hatte - ich wünschte, Monitor wäre eine instanziierbare Klasse gewesen.

(ich nehme an, du bist nur tatsächlich aus dem Wörterbuch von mehreren Threads zu lesen? Es ist nicht sicher ist Wörterbücher für Multi-Threaded-Lese-/Schreib zu verwenden.)

+0

Ich schreibe nur in die Warteschlange, wenn sie leer ist. Ich habe diesen Teil in meinem obigen Code zur Vereinfachung weggelassen. Aber die Warteschlange sollte in diesem Fall gesperrt werden, daher sollte das Schreiben keine Probleme bereiten. – Ben

+1

Die Verwendung eines einfachen 'System.Object' funktioniert jedoch nicht für eine unbekannte Anzahl von Sperrobjekten. – Ben

+0

@Ben: Sie können ein Wörterbuch mit dedizierten Sperrobjekten verwenden, eines für jede Instanz von "Queue ". Ich sehe immer noch nicht, warum Sie 'Queue ' statt ['ConcurrentQueue '] (http://stackoverflow.com/a/16984743/45914) verwenden. – jason

2

Die Tatsache, dass es ein Element in a Wörterbuch ist weitgehend irrelevant - solange es eine Referenzart ist (die Queue<string>ist) - dann wird jede Warteschlange, wenn sie aus dem Wörterbuch abgerufen wird, die gleiche object Instanz jedes Mal sein. Dies bedeutet, dass es mit dem Sperren auf der Warteschlangenebene einwandfrei funktioniert.

Also im Grunde: ja, das sollte gut funktionieren - solange die Enqueue das gleiche pro Warteschlange Sperren tut. Wie Jon bemerkt - ob Sie sollten tun, das ist eine andere Frage.

Ich persönlich bin immer noch der Meinung, dass Monitor eine nicht-statische Typ sein sollte, und dass Sie nur Monitor Instanzen sperren könnte, anstatt jede object.

1

Meine Frage ist also, ob das Sperren eines Objekts in einem Wörterbuch funktioniert - vorausgesetzt, der Wert eines Schlüssels (die Warteschlange) wird nie geändert.

auf den Code der Suche hier:

lock (queue) { 
    if (queue.Count() > 0) { 
     res = queue.Dequeue(); 
    } 
} 

Sie können, aber ich würde nicht dies tun. Sie sollten never lock on the object itself, da Sie möglicherweise konkurrieren mit andere Threads von Code, die auf das gleiche Objekt, einschließlich Queue<T> selbst sperren (wer könnte auf this sperren).

Also sollten Sie mindestens ein dediziertes Sperrobjekt für jede Warteschlange erstellen.

Aber gibt es einen Grund, dass Sie nicht ConcurrentQueue<T> verwenden? Das wäre die einfachste Lösung und verlagert die Last, es richtig in das Framework zu bringen.

Verwandte Themen