2013-06-07 16 views
6

Ho più code a cui si accede da più thread. Per raggiungere thread-safety, ho fatto quanto segue:Posso usare gli elementi del dizionario come oggetti di blocco?

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; 
} 

ho potuto anche bloccare MyQueues, ma poi avrei bloccare più del necessario. Quindi la mia domanda è, se il blocco di un oggetto contenuto in un dizionario funziona, supponendo che il valore di una chiave (la coda) non venga mai modificato.

+0

La tua domanda si legge più come una dichiarazione. Qual è la tua domanda di nuovo? –

+0

Non blocchi gli oggetti, blocchi * i riferimenti agli oggetti *. Quindi, in altre parole, se il valore dell'oggetto cambia non influenza la serratura. – Nolonar

+0

@Nononar no, si blocca l'oggetto stesso. Potresti avere 17 riferimenti allo stesso oggetto: bloccerebbero tutti la stessa cosa. –

risposta

6

È possibile - ma io generalmente non. Personalmente di solito cerco di bloccare semplici istanze System.Object che non vengono utilizzate per nient'altro, e idealmente non sono nemmeno esposte a nessun codice se non il blocco di classe su di esse. In questo modo puoi essere assolutamente sicuro che nient'altro si bloccherà.

In questo caso sembra che hai il controllo sulle code in modo da sapere che non saranno utilizzati da altro codice, ma è possibile che il codice all'interno Queue<T> si blocca su this. Probabilmente non è il caso, ma è il tipo di cosa di cui mi preoccuperei.

Fondamentalmente, vorrei che .NET non avesse preso l'approccio di Java di "un monitor per ogni oggetto" - vorrei che lo Monitor fosse stato una classe istantanea.

(presumo che sei solo in realtà lettura dal dizionario da più thread? Non è sicuro da usare dizionari per il multi-threaded di lettura/scrittura.)

+0

Scrivo solo in coda quando è vuoto. Ho omesso quella parte del mio codice qui sopra per semplicità. Ma la coda dovrebbe essere bloccata in quel caso, quindi scrivere non dovrebbe creare problemi. – Ben

+1

Tuttavia, l'uso di un semplice 'System.Object' non funziona per un numero sconosciuto di oggetti di blocco. – Ben

+0

@ Ben: è possibile utilizzare un dizionario di oggetti di blocco dedicati, uno per ogni istanza di 'Coda '. Non vedo ancora perché stai usando 'Queue ' invece di ['ConcurrentQueue '] (http://stackoverflow.com/a/16984743/45914). – jason

2

Il fatto che si tratta di un elemento in una Il dizionario è in gran parte irrilevante - purché sia ​​un tipo di riferimento (che Queue<string>è) - quindi ogni coda, quando recuperata dal dizionario, sarà la stessa istanza object ogni volta. Ciò significa che funzionerà perfettamente ragionevolmente con il blocco a livello di coda.

Quindi in sostanza: sì, dovrebbe funzionare correttamente, a condizione che lo Enqueue esegua lo stesso blocco per la coda. Come nota Jon - che tu sia dovrebbe fare fare questa è un'altra domanda.

Personalmente, sono ancora dell'opinione che Monitor avrebbe dovuto essere un tipo non statico e che è possibile bloccare solo istanze Monitor anziché object.

1

Quindi la mia domanda è, se il blocco di un oggetto contenuto in un dizionario funziona, supponendo che il valore di una chiave (la coda) non venga mai modificato.

Guardando il codice qui:

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

È possibile , ma vorrei non farlo. Si dovrebbe never lock on the object itself, come si potrebbe essere in concorrenza con altri thread di codice che si bloccherà sullo stesso oggetto, tra cui Queue<T> stesso (chi potrebbe bloccare this).

Quindi, come minimo, è necessario creare un oggetto di blocco dedicato per ogni coda.

Ma, c'è un motivo per cui non si sta utilizzando ConcurrentQueue<T>? Questa sarebbe la soluzione più semplice e sposta l'onere di farlo correttamente nel Framework.

Problemi correlati