Alessandro Del Sole's Blog

{ A programming space about Microsoft® .NET® }
posts - 1909, comments - 2047, trackbacks - 352

My Links

News

Your host

This is me! Questo spazio è dedicato a Microsoft® .NET®, di cui sono molto appassionato :-)

Cookie e Privacy

Microsoft MVP

My MVP Profile

Microsoft Certified Professional

Microsoft Specialist

Xamarin Certified Mobile Developer

Il mio libro su VB 2015!

Pre-ordina il mio libro su VB 2015 Pre-ordina il mio libro "Visual Basic 2015 Unleashed". Clicca sulla copertina per informazioni!

Il mio libro su WPF 4.5.1!

Clicca sulla copertina per informazioni! E' uscito il mio libro "Programmare con WPF 4.5.1". Clicca sulla copertina per informazioni!

These postings are provided 'AS IS' for entertainment purposes only with absolutely no warranty expressed or implied and confer no rights.
If you're not an Italian user, please visit my English blog

Le vostre visite

I'm a VB!

Guarda la mia intervista a Seattle

Follow me on Twitter!

Altri spazi

GitHub
I miei progetti open-source su GitHub

Article Categories

Archives

Post Categories

Image Galleries

Privacy Policy

Collezioni "concurrent" in .NET 4: BlockingCollection(Of T)

Dopo aver parlato della ConcurrentDictionary nel precedente post, stavolta introduciamo l'ultima e più interessante delle collezioni thread-safe introdotte da .NET Framework 4.0, ossia la BlockingCollection(Of T). Questa collezione è molto interessante per i seguenti motivi:

  • se un thread tenta di accedere alla collezione fin tanto che questa è vuota (ad eccezione dell'aggiunta di un elemento), il thread stesso viene bloccato finchè alla collezione non viene aggiunto almeno un elemento;
  • può essere marcata come completa, cosicchè altri thread non possano aggiungere elementi e, in caso ciò avvenga, viene sollevata una InvalidOperationException;
  • al contrario si possono utilizzare metodi che non vengono bloccati e, nel qual caso, se la collezione è completa, il thread viene messo in attesa finchè nella collezione non si libera un posto.

Il seguente codice Visual Basic 2010 mostra un esempio d'uso:

        Dim bc As New BlockingCollection(Of String)

 

        bc.Add("Primo")

        bc.Add("Secondo")

        bc.Add("Terzo")

        bc.Add("Quarto")

 

        'Marca la collezione come completa

        bc.CompleteAdding()

 

        'Solleva una InvalidOperationException

        'bc.Add("Quinto")

 

        'Rimuove un elemento (FIFO)

        'in questo caso "Primo"

        Dim risultato = bc.Take()

        Console.WriteLine(risultato)

Dietro le scene, la BlockingCollection non è un vero e proprio storage ma utilizza una ConcurrentQueue a cui vengono aggiunte funzionalità di blocco. Per tale ragione, la collezione in questione utilizza un approccio FIFO (First-in, First-out). Esistono inoltre dei metody TryAdd e TryTake che non subiscono il blocco ma mettono il thread in condizione di attesa, come precedentemente descritto. Un'altra caratteristica è che si può impostare, attraverso il costruttore, il numero massimo di elementi accettabili, che viene poi restituito dalla proprietà BoundedCapacity. Altre proprietà interessanti sono IsAddingCompleted, che restituisce vero o falso a seconda che la collezione sia marcata come completa tramite il metodo CompleteAdding, e IsCompleted che restituisce la stessa cosa ma solo se la collezione è anche vuota. Ora ci si chiederà come funziona il discorso del mettere in attesa un thread finchè la collezione non contiene un qualche elemento. Il seguente codice fa uso del metodo Parallel.Invoke (che richiede una direttiva Imports System.Threading.Tasks) che fa parte della Task Parallel Library inerente il parallel computing con .NET 4, che avvia più task simultanei:

        Dim bc As New BlockingCollection(Of String)

 

        Parallel.Invoke(Sub()

                            Dim result = bc.Take

                            Console.WriteLine(result)

                        End Sub, Sub()

                                     bc.Add("Primo")

                                 End Sub)

In sostanza il primo task tenta di rimuovere un elemento ma la collezione è vuota, così attende che l'altro task inserisca l'elemento che può poi essere prelevato. Chiaramente questo avviene se il primo task nel codice viene effettivamente eseguito per primo, ma lavorando in parallelo potrebbe non essere così, ma il concetto dovrebbe essere chiaro.

Un'ulteriore caratteristica è la possibilità di aggiungere lo stesso elemento a più istanze della collezione in un sol colpo. Il seguente frammento mostra come, dato un array di BlockingCollection, sia possibile aggiungere un elemento a tutte le istanze nell'array:

 

        Dim collection1 As New BlockingCollection(Of String)

        Dim collection2 As New BlockingCollection(Of String)

 

        Dim collezioni(1) As BlockingCollection(Of String)

        collezioni(0) = collection1

        collezioni(1) = collection2

 

        BlockingCollection(Of String).AddToAny(collezioni,

                                               "elementoComune")

Per rimuovere un elemento si usa il metodo TakeFromAny. Analogamente ci sono dei metodi "non-blocking" come TryAddToAny e TryTakeFromAny.

Alessandro

Print | posted on mercoledì 13 gennaio 2010 23:58 | Filed Under [ Parallel Programming ]

Powered by:
Powered By Subtext Powered By ASP.NET