2010-06-21 2 views
5

Credo che questo funziona, ho provato con più thread simultanei (anche se non in modo esaustivo per le condizioni di competizione e deadlock):C# .NET 4.0 ConcurrentDictionary: TryRemove all'interno di un blocco?

public static System.Collections.Concurrent.ConcurrentDictionary<string, item> dict = 
     new System.Collections.Concurrent.ConcurrentDictionary<string, item>(); 
public static item dump; 

...

foreach (System.Collections.Generic.KeyValuePair<string, item> x in dict) 
{ 
    lock (x.Value) 
    { 
     if (x.Value.IsCompleted) 
     { 
      dict.TryRemove(x.Key, out dump); 
     } 
    } 
} 

Questa domanda è una sorta di continuazione di questa domanda:

Can I remove items from a ConcurrentDictionary from within an enumeration loop of that dictionary?

E questa domanda:

Updating fields of values in a ConcurrentDictionary

In che sto facendo due manovre "rischiose":

  1. valori Rimozione da un ConcurrentDictionary, mentre allo stesso tempo l'enumerazione attraverso di essa (che sembra essere ok).
  2. Blocco della parte Value di un ConcurrentDictionary. Necessario perché la manipolazione dei campi del valore non è thread-safe, solo la manipolazione dei valori stessi di ConcurrentDictionary è thread-safe (il codice sopra è uno snippet di un blocco di codice più grande in cui i campi di valori sono effettivamente manipolati).

risposta

4

La rimozione di valori da un dizionario concorrente durante l'iterazione è soddisfacente. Potrebbe avere delle implicazioni sulle prestazioni (non ne sono sicuro) ma dovrebbe funzionare.

Nota che non stai bloccando qualcosa di interno a ConcurrentDictionary - stai bloccando il monitor associato a un oggetto item. Personalmente non vorrei farlo: o questi elementi dovrebbero essere thread-safe (rendendo comunque possibile manipolarli comunque) o (preferibilmente) immutabili in modo da poterli osservare da qualsiasi thread senza bloccarli. Oppure potresti semplicemente rendere la singola proprietà che stai controllando thread-safe, ovviamente. Documenta qualunque cosa tu faccia!

Infine, l'utilizzo di out dump sembra leggermente dubbio. Il punto è avere qualcosa da dare a TryRemove? Se è così, userei una variabile locale invece di una statica.

+1

grazie Jon sì: discarica è destinata ad essere un ripostiglio inutile.lo trasformerò in una variabile locale, come ambito globale la static statica è una vulnerabilità le proprietà all'interno dell'elemento: bloccherò le singole proprietà piuttosto che l'articolo, come suggerito. potrebbe esserci un modo più elegante per gestire questo, ma queste proprietà verranno modificate in un thread, lette in un altro e rimosse a livello di articolo in un terzo applausi! – circletimessquare

0

Un'ottima alternativa che ho trovato recentemente riguarda la rimozione solo se è la corrispondenza chiave/valore, il che significa che è possibile garantire la rimozione di un oggetto (preferibile un tipo di valore, non un tipo di riferimento) che non c'era modificare. Esempio:

Ora supponiamo che le due righe seguenti siano in esecuzione in uno scenario concomitante/multithread.

 cc.AddOrUpdate("1", 2, (a,b) => b + 1); 

     var removeSuccess = ((ICollection<KeyValuePair<string, int>>)cc).Remove(
    new KeyValuePair<string, int>("1", 1)); 

Se il valore non cambia verrà rimosso "1" con successo, altrimenti non riuscirà, perché avete già un nuovo valore per la stessa chiave.

Per ulteriori informazioni di controllo di seguito: http://thargy.com/2012/09/the-hidden-secret-of-the-concurrent-dictionary/ o http://blogs.msdn.com/b/pfxteam/archive/2011/04/02/10149222.aspx