Procedura: utilizzare un pool di thread (C# e Visual Basic)

La creazione di un pool di thread è una forma di multithreading che prevede l'aggiunta di attività a una coda e l'avvio automatico di tali attività nel corso della creazione dei thread.Per ulteriori informazioni, vedere Creazione di pool di thread (C# e Visual Basic).

Nell'esempio seguente viene utilizzato il pool di thread di .NET Framework per calcolare il risultato Fibonacci relativo a dieci numeri compresi tra 20 e 40.Ogni risultato Fibonacci viene rappresentato dalla classe Fibonacci che fornisce un metodo denominato ThreadPoolCallback per l'esecuzione del calcolo.Viene creato un oggetto che rappresenta ogni valore Fibonacci, quindi il metodo ThreadPoolCallback viene passato a QueueUserWorkItem, che assegna un thread disponibile del pool all'esecuzione del metodo.

Poiché a ogni oggetto Fibonacci viene assegnato un valore semi-casuale da calcolare e poiché ogni thread sarà in competizione per ottenere il tempo del processore, non è possibile prevedere quanto tempo richiederà il calcolo di tutti e dieci i risultati.Per questo motivo a ogni oggetto Fibonacci viene passata un'istanza della classe ManualResetEvent durante la costruzione.Una volta completato il calcolo, ogni oggetto segnala l'oggetto evento fornito. In questo modo il thread primario può bloccare l'esecuzione con WaitAll finché tutti e dieci gli oggetti Fibonacci non hanno calcolato un risultato.Il metodo Main visualizza quindi ogni risultato Fibonacci.

Esempio

Imports System.Threading

Module Module1

    Public Class Fibonacci
        Private _n As Integer
        Private _fibOfN
        Private _doneEvent As ManualResetEvent

        Public ReadOnly Property N() As Integer
            Get
                Return _n
            End Get
        End Property

        Public ReadOnly Property FibOfN() As Integer
            Get
                Return _fibOfN
            End Get
        End Property

        Sub New(ByVal n As Integer, ByVal doneEvent As ManualResetEvent)
            _n = n
            _doneEvent = doneEvent
        End Sub

        ' Wrapper method for use with the thread pool.
        Public Sub ThreadPoolCallBack(ByVal threadContext As Object)
            Dim threadIndex As Integer = CType(threadContext, Integer)
            Console.WriteLine("thread {0} started...", threadIndex)
            _fibOfN = Calculate(_n)
            Console.WriteLine("thread {0} result calculated...", threadIndex)
            _doneEvent.Set()
        End Sub

        Public Function Calculate(ByVal n As Integer) As Integer
            If n <= 1 Then
                Return n
            End If
            Return Calculate(n - 1) + Calculate(n - 2)
        End Function

    End Class


    <MTAThread()> 
    Sub Main()
        Const FibonacciCalculations As Integer = 9 ' 0 to 9

        ' One event is used for each Fibonacci object
        Dim doneEvents(FibonacciCalculations) As ManualResetEvent
        Dim fibArray(FibonacciCalculations) As Fibonacci
        Dim r As New Random()

        ' Configure and start threads using ThreadPool.
        Console.WriteLine("launching {0} tasks...", FibonacciCalculations)

        For i As Integer = 0 To FibonacciCalculations
            doneEvents(i) = New ManualResetEvent(False)
            Dim f = New Fibonacci(r.Next(20, 40), doneEvents(i))
            fibArray(i) = f
            ThreadPool.QueueUserWorkItem(AddressOf f.ThreadPoolCallBack, i)
        Next

        ' Wait for all threads in pool to calculate.
        WaitHandle.WaitAll(doneEvents)
        Console.WriteLine("All calculations are complete.")

        ' Display the results.
        For i As Integer = 0 To FibonacciCalculations
            Dim f As Fibonacci = fibArray(i)
            Console.WriteLine("Fibonacci({0}) = {1}", f.N, f.FibOfN)
        Next
    End Sub

End Module
using System;
using System.Threading;

public class Fibonacci
{
    private int _n;
    private int _fibOfN;
    private ManualResetEvent _doneEvent;

    public int N { get { return _n; } }
    public int FibOfN { get { return _fibOfN; } }

    // Constructor.
    public Fibonacci(int n, ManualResetEvent doneEvent)
    {
        _n = n;
        _doneEvent = doneEvent;
    }

    // Wrapper method for use with thread pool.
    public void ThreadPoolCallback(Object threadContext)
    {
        int threadIndex = (int)threadContext;
        Console.WriteLine("thread {0} started...", threadIndex);
        _fibOfN = Calculate(_n);
        Console.WriteLine("thread {0} result calculated...", threadIndex);
        _doneEvent.Set();
    }

    // Recursive method that calculates the Nth Fibonacci number.
    public int Calculate(int n)
    {
        if (n <= 1)
        {
            return n;
        }

        return Calculate(n - 1) + Calculate(n - 2);
    }
}

public class ThreadPoolExample
{
    static void Main()
    {
        const int FibonacciCalculations = 10;

        // One event is used for each Fibonacci object.
        ManualResetEvent[] doneEvents = new ManualResetEvent[FibonacciCalculations];
        Fibonacci[] fibArray = new Fibonacci[FibonacciCalculations];
        Random r = new Random();

        // Configure and start threads using ThreadPool.
        Console.WriteLine("launching {0} tasks...", FibonacciCalculations);
        for (int i = 0; i < FibonacciCalculations; i++)
        {
            doneEvents[i] = new ManualResetEvent(false);
            Fibonacci f = new Fibonacci(r.Next(20, 40), doneEvents[i]);
            fibArray[i] = f;
            ThreadPool.QueueUserWorkItem(f.ThreadPoolCallback, i);
        }

        // Wait for all threads in pool to calculate.
        WaitHandle.WaitAll(doneEvents);
        Console.WriteLine("All calculations are complete.");

        // Display the results.
        for (int i= 0; i<FibonacciCalculations; i++)
        {
            Fibonacci f = fibArray[i];
            Console.WriteLine("Fibonacci({0}) = {1}", f.N, f.FibOfN);
        }
    }
}

Di seguito viene riportato un esempio dell'output.

launching 10 tasks...
thread 0 started...
thread 1 started...
thread 1 result calculated...
thread 2 started...
thread 2 result calculated...
thread 3 started...
thread 3 result calculated...
thread 4 started...
thread 0 result calculated...
thread 5 started...
thread 5 result calculated...
thread 6 started...
thread 4 result calculated...
thread 7 started...
thread 6 result calculated...
thread 8 started...
thread 8 result calculated...
thread 9 started...
thread 9 result calculated...
thread 7 result calculated...
All calculations are complete.
Fibonacci(38) = 39088169
Fibonacci(29) = 514229
Fibonacci(25) = 75025
Fibonacci(22) = 17711
Fibonacci(38) = 39088169
Fibonacci(29) = 514229
Fibonacci(29) = 514229
Fibonacci(38) = 39088169
Fibonacci(21) = 10946
Fibonacci(27) = 196418

Vedere anche

Riferimenti

Mutex

WaitAll

ManualResetEvent

Set

ThreadPool

QueueUserWorkItem

ManualResetEvent

Concetti

Creazione di pool di thread (C# e Visual Basic)

Monitor

Altre risorse

Threading (C# e Visual Basic)

Come sincronizzare l'accesso a una risorsa condivisa in un ambiente multithreading mediante Visual C# .NET

Sicurezza in .NET Framework