2013-04-08 18 views
9

Sto cercando di incrementare un elemento in un elenco in C#, ma ho bisogno che sia thread-safe, quindi il conteggio non viene influenzato.Incremento sicuro del thread in C#

So che si può fare questo per gli interi:

Interlocked.Increment(ref sdmpobjectlist1Count);

, ma questo non funziona in un elenco che ho il seguente finora:

lock (padlock) 
{ 
    DifferenceList[diff[d].PropertyName] = DifferenceList[diff[d].PropertyName] + 1; 
} 

So che questo funziona, ma Non sono sicuro se c'è un altro modo per farlo?

+14

Perché hai bisogno di un altro modo, se funziona in questo modo? –

+0

Stai cercando un meccanismo di blocco non esclusivo? –

+0

http://msdn.microsoft.com/en-us/library/system.threading.monitor.aspx – CSharpie

risposta

1

Come diceva David Heffernan, ConcurrentDictionary dovrebbe fornire prestazioni migliori. Tuttavia, il guadagno di prestazioni potrebbe essere trascurabile in base alla frequenza con cui più thread tentano di accedere alla cache.

using System; 
using System.Collections.Concurrent; 
using System.Threading; 

namespace ConcurrentCollections 
{ 
    class Program 
    { 
     static void Main() 
     { 
      var cache = new ConcurrentDictionary<string, int>(); 

      for (int threadId = 0; threadId < 2; threadId++) 
      { 
       new Thread(
        () => 
        { 
         while (true) 
         { 
          var newValue = cache.AddOrUpdate("key", 0, (key, value) => value + 1); 
          Console.WriteLine("Thread {0} incremented value to {1}", 
           Thread.CurrentThread.ManagedThreadId, newValue); 
         } 

        }).Start(); 
      } 

      Thread.Sleep(TimeSpan.FromMinutes(2)); 
     } 
    } 
} 
+0

La funzione di aggiornamento non è atomica in una chiamata AddOrUpdate. https://msdn.microsoft.com/en-us/library/dd287191(v=vs.110).aspx – Ryan

+0

Questo commento indica semplicemente "il codice potrebbe essere eseguito più di una volta prima che abbia esito positivo". Funziona fuori dalla serratura, fondamentalmente. Quindi ottiene il valore esistente, ne aggiunge 1, estrae un blocco e quindi prova a scriverlo. Se il valore esistente è cambiato nel frattempo, ripete il processo fino a quando non riesce. – mjwills

-1

controllare la variabile bloccata su "lucchetto", normalmente, è possibile definirla come private static Object padLock = new Object(). se non lo definisci come statico, ogni oggetto ha la sua copia, quindi non funzionerà.

+4

Dipende dai dati. Se i dati non sono statici, non è necessario che l'oggetto lock sia statico; starebbe inutilmente sincronizzando con thread che non stanno cercando di accedere agli stessi dati. – Servy

1

Se si utilizza un List<int[]> piuttosto che un List<int>, e avere ogni elemento della lista sia una matrice di singolo elemento, si sarà in grado di fare Increment(ref List[whatever][0]) e l'abbiano in essere atomica. Si potrebbe migliorare l'efficienza dello storage leggermente se si definisce

class ExposedFieldHolder<T> {public T Value;} 

e poi usato un List<ExposedFieldHolder<int>> e utilizzato la dichiarazione Increment(ref List[whatever].Value) per eseguire l'incremento. Le cose potrebbero essere più efficienti se i tipi built-in fornissero un mezzo per esporre un oggetto come ref o classi derivate consentite sufficiente accesso al loro interno per fornire tali capacità da soli. Non lo fanno, tuttavia, quindi è necessario definire da zero i propri tipi di raccolta o incapsulare ciascun elemento nel proprio oggetto di classe [utilizzando una matrice o una classe wrapper].

+0

A meno che tu non abbia una ragione molto specifica per scrivere la tua raccolta thread-safe, nella maggior parte dei casi sarai molto meglio con uno fornito con TPL. –