DarioSantarelli.Blog("UgiDotNet");

<sharing mode=”On” users=”*” />
posts - 176, comments - 144, trackbacks - 3

My Links

News


This is my personal blog. These postings are provided "AS IS" with no warranties, and confer no rights.

logo linkedIn logo Twitter logo FaceBook logo RSS logo Email

Logo DotNetMarche
Logo XPUG Marche



Tag Cloud

Archives

Post Categories

My English Blog

domenica 3 luglio 2011

System.Collections.Concurrent: via tutti i lock!

Per garantire la thread-safety nell’accesso a collezioni di oggetti in contesti multi-thread, fino ad oggi siamo stati abituati ad utilizzare i più svariati meccanismi di lock, magari prevedendo diversi livelli di granularità.
In questo ambito il framework 4.0 fornisce il namespace System.Collections.Concurrent che offre un set di classi thread-safe che si possono usare al posto di quelle di System.Collections e System.Collections.Generic.

Anzitutto, salutiamo con una certa soddisfazione la classe ConcurrentDictionary<TKey, TValue>, versione thread-safe della classe Dictionary.

Vengono forniti poi tre oggetti che implementano IProducerConsumerCollection<T>, un’interfaccia che definisce due metodi TryAdd e TryTake per scenari “producer/consumer”, ovvero scenari in cui più thread aggiungono o rimuovono elementi dalla stessa collection in modo concorrente. Gli oggetti in questione sono:

  • ConcurrentBag<T>: implementazione thread-safe di una collezione non ordinata di elementi (eventualmente duplicabili). Questo oggetto è particolarmente ottimizzato per scenari in cui lo stesso thread produce e consuma gli elementi del bag.
  • ConcurrentQueue<T>: versione concorrente di una coda FIFO. A differenza di quanto si sente dire spesso erroneamente, questa classe non costituisce un semplice wrapper della classe Queue ( tipo Queue.Synchronized() ), bensì qualcosa di più potente e performante che internamente fa uso di meccanismi di sincronizzazione e validazione più ottimizzati basati sulle classi SpinWait e Interlocked.
  • ConcurrentStack<T>: versione concorrente di uno stack LIFO. 

Infine abbiamo l’oggetto BlockingCollection<T>, che di fatto costituisce una classe di più alto livello. Una BlockingCollection è a tutti gli effetti un wrapper di un oggetto che implementa l’interfaccia IProducerConsumerCollection<T> (come i sopra citati ConcurrentBag<T>, ConcurrentQueue<T> e ConcurrentStack<T>). Ciò significa che di suo non implementa un meccanismo di storage interno, bensì introduce soltanto la logica di gestione thread-safe per scenari producer/consumer. Infatti, se non forniamo al costruttore un IProducerConsumerCollection, per default viene istanziata internamente una ConcurrentQueue (FIFO). Poiché la BlockingCollection è utile come buffer di scambio condiviso tra più thread, essa fornisce gratis anche dei meccanismi di blocco (metodi Add() e Take()) grazie ai quali possiamo fare in modo che i thread “producer” si blocchino se la collezione è piena (aspettando quindi che almeno un elemento venga rimosso dalla collezione) oppure viceversa che i thread “consumer” si blocchino quando cercano di rimuovere un elemento dalla collection interna vuota.

posted @ domenica 3 luglio 2011 14.31 | Feedback (0) | Filed Under [ .NET ]

Powered by: