Pool de threads managés

La classe ThreadPool fournit à votre application un pool de threads de travail qui sont managés par le système, vous permettant de vous concentrer sur les tâches de l'application plutôt que sur la gestion des threads. Dans le cas de petites tâches qui exigent un traitement en arrière-plan, le pool de threads managé représente un moyen facile de tirer parti de plusieurs threads. Par exemple, en commençant par .NET Framework version 4, vous pouvez créer les objets Task et Task<TResult>, qui effectuent des tâches asynchrones sur des threads de pool de threads.

RemarqueRemarque

Démarrant avec le .NET Framework version 2.0 Service Pack 1, le débit du pool de threads est amélioré considérablement dans les trois zones clés identifiées comme goulots d'étranglement dans les version finale précédentes du .NET Framework: mettre en file d'attente des tâches, distribuer des threads ThreadPool, et distribuer des threads de terminaison d'E/S.Pour utiliser cette fonctionnalité, votre application doit cibler le .NET Framework version 3.5 ou une version ultérieure.

Pour les tâches en arrière-plan qui interagissent avec l'interface utilisateur, le .NET Framework version 2.0 fournit également la classe BackgroundWorker qui communique à l'aide d'événements déclenchés sur le thread d'interface utilisateur.

Le .NET Framework utilise des threads du pool de threads dans de nombreuses circonstances, notamment pour la terminaison des E/S asynchrones, les rappels de la minuterie, les opérations d'attente inscrites, les appels de méthodes asynchrones utilisant des délégués, et des connexions de socket System.Net.

Scénarios où l'utilisation de threads du pool de threads est déconseillée

Il existe plusieurs scénarios où il est plus approprié de créer et gérer vos propres threads au lieu d'utiliser les threads du pool de threads :

  • Vous avez besoin d'un thread de premier plan.

  • Il est nécessaire que le thread ait une priorité particulière.

  • Certaines tâches provoquent le blocage du thread pendant de longues périodes. Le pool de threads ayant un nombre maximal de threads, un grand nombre de threads bloqués dans le pool peut empêcher le démarrage de tâches.

  • Vous devez placer des threads dans un thread cloisonné (STA, Single-Threaded Apartment). Tous les threads de ThreadPool sont dans le MTA (Multithreaded Apartment).

  • Une identité stable doit être associée au thread ou un thread doit être dédié à une tâche.

Caractéristiques du pool de threads

Les threads du pool de threads sont des threads d'arrière-plan. Consultez Threads de premier plan et d'arrière-plan. Chaque thread utilise la taille de pile et l'ordre de priorité d'exécution par défaut. Il se trouve dans le MTA (Multithreaded Apartment).

Il existe un seul pool de threads par processus.

Exceptions dans les threads d'un pool de threads

Les exceptions non gérées sur les threads du pool de threads mettent un terme au processus. Il existe trois exceptions à cette règle :

  • Un ThreadAbortException est levé dans un thread de pool de threads en raison d'un appel à Abort.

  • Un AppDomainUnloadedException est levé dans un thread du pool de threads, car le domaine d'application est en cours de déchargement.

  • Le Common Language Runtime ou un processus hôte met fin au thread.

Pour plus d'informations, consultez Exceptions dans les threads managés.

RemarqueRemarque

Dans les versions 1.0 et 1.1 du .NET Framework, le Common Language Runtime intercepte en mode silencieux les exceptions non gérées dans les threads du pool de threads.Cela peut endommager l'état de l'application et éventuellement provoquer le blocage des applications, ce qui peut être très difficile à déboguer.

Nombre maximal de threads de pool de threads

Le nombre des opérations qui peuvent être mises en file d'attente dans le pool de threads est limité uniquement par la mémoire disponible ; toutefois, le pool de threads limite le nombre de threads simultanément actifs dans le processus. En commençant par .NET Framework version 4, la taille par défaut du pool de threads pour un processus dépend de plusieurs facteurs, tels que la taille de l'espace d'adressage virtuel. Un processus peut appeler la méthode GetMaxThreads pour déterminer le nombre de threads.

Vous pouvez contrôler le nombre maximal de threads en utilisant les méthodes GetMaxThreads et SetMaxThreads.

RemarqueRemarque

Dans les versions 1.0 et 1.1 du .NET Framework, la taille du pool de threads ne peut pas être définie à partir du code managé.Le code qui héberge le Common Language Runtime peut définir cette taille à l'aide de CorSetMaxThreads, défini dans mscoree.h.

Valeurs minimales du pool de threads

Le pool de threads fournit de nouveaux threads de travail ou threads de terminaison d'E/S à la demande jusqu'à ce qu'il atteigne un minimum spécifié pour chaque catégorie. Vous pouvez utiliser la méthode GetMinThreads pour obtenir ces valeurs minimales.

RemarqueRemarque

Lorsqu'une demande est faible, le nombre réel de threads de pool de threads peut tomber en dessous des valeurs minimales.

Lorsqu'une valeur minimale est atteinte, le pool de threads peut créer des threads supplémentaires ou attendre que certaines tâches s'achèvent. En commençant par .NET Framework 4, le pool de threads crée et détruit des threads de travail afin d'optimiser le débit, qui est défini en tant que nombre de tâches qui s'achèvent par unité de temps. Un nombre insuffisant de threads risque d'empêcher une utilisation optimale des ressources disponibles, tandis qu'un trop grand nombre de threads peut augmenter le conflit de ressources.

Remarque AttentionAttention

Vous pouvez utiliser la méthode SetMinThreads pour augmenter le nombre minimal de threads inactifs.Toutefois, augmenter inutilement ces valeurs peut provoquer des problèmes de performances.Si un trop grand nombre de tâches démarrent en même temps, elles risquent toutes de s'exécuter avec lenteur.Dans la plupart des cas, le pool de threads sera plus performant avec son propre algorithme pour allouer des threads.

Vérifications de la sécurité ignorées

Le pool de threads fournit également les ThreadPool.UnsafeQueueUserWorkItem et méthodes ThreadPool.UnsafeRegisterWaitForSingleObject. Utilisez ces méthodes uniquement lorsque vous êtes certain que la pile de l'appelant n'est pas concernée par toutes les vérifications de sécurité effectuées pendant l'exécution de la tâche en file d'attente. QueueUserWorkItemet RegisterWaitForSingleObject capturent toutes deux la pile de l'appelant, qui est fusionnée dans la pile du thread du pool de threads lorsque le thread commence à exécuter une tâche. Si une vérification de la sécurité est nécessaire, l'ensemble de la pile doit être vérifié. Bien que la vérification assure la sécurité, cette vérification s'effectue au détriment des performances.

Utilisation du pool de threads

En commençant par .NET Framework 4, la façon la plus simple d'utiliser le pool de threads est d'utiliser Bibliothèque parallèle de tâches. Par défaut, les types parallèles de bibliothèque tels que Task et Task<TResult> utilisent des threads de pool de threads pour exécuter les tâches. Vous pouvez également utiliser le pool de threads en appelant ThreadPool.QueueUserWorkItem à partir du code managé (ou CorQueueUserWorkItem à partir du code non managé) et en passant un délégué WaitCallback représentant la méthode qui exécute la tâche. Une autre façon d'utiliser le pool de threads est de placer en file d'attente les éléments de travail liés à une opération d'attente en utilisant la méthode ThreadPool.RegisterWaitForSingleObject et en passant un WaitHandle qui, une fois signalé ou expiré, appelle la méthode représentée par le délégué WaitOrTimerCallback. Les threads de pools de threads sont utilisés pour appeler des méthodes de rappel.

Exemples de ThreadPool

Les exemples de code de cette section présentent le pool de threads à l'aide de la classe Task et des méthodes ThreadPool.QueueUserWorkItem et ThreadPool.RegisterWaitForSingleObject.

  • Exécution de tâches asynchrones avec la bibliothèque parallèle de tâches

  • Exécution de code de façon asynchrone avec QueueUserWorkItem

  • Indication des données de tâche pour QueueUserWorkItem

  • Utilisation de RegisterWaitForSingleObject

Exécution de tâches asynchrones avec la bibliothèque parallèle de tâches

L'exemple suivant indique comment créer et utiliser un objet Task en appelant la méthode TaskFactory.StartNew. Pour obtenir un exemple qui utilise la classe Task<TResult> pour retourner une valeur à partir d'une tâche asynchrone, consultez Comment : retourner une valeur à partir d'une tâche.

Imports System.Threading
Imports System.Threading.Tasks
Module StartNewDemo

    ' Demonstrated features:
    '   Task ctor()
    '   Task.Factory
    '   Task.Wait()
    '   Task.RunSynchronously()
    ' Expected results:
    '   Task t1 (alpha) is created unstarted.
    '   Task t2 (beta) is created started.
    '   Task t1's (alpha) start is held until after t2 (beta) is started.
    '   Both tasks t1 (alpha) and t2 (beta) are potentially executed on threads other than the main thread on multi-core machines.
    '   Task t3 (gamma) is executed synchronously on the main thread.
    ' Documentation:
    '   https://msdn.microsoft.com/en-us/library/system.threading.tasks.task_members(VS.100).aspx
    Private Sub Main()
        Dim action As Action(Of Object) = Sub(obj As Object)
                                              Console.WriteLine("Task={0}, obj={1}, Thread={2}", Task.CurrentId, obj.ToString(), Thread.CurrentThread.ManagedThreadId)
                                          End Sub

        ' Construct an unstarted task
        Dim t1 As New Task(action, "alpha")

        ' Cosntruct a started task
        Dim t2 As Task = Task.Factory.StartNew(action, "beta")

        ' Block the main thread to demonstate that t2 is executing
        t2.Wait()

        ' Launch t1 
        t1.Start()

        Console.WriteLine("t1 has been launched. (Main Thread={0})", Thread.CurrentThread.ManagedThreadId)

        ' Wait for the task to finish.
        ' You may optionally provide a timeout interval or a cancellation token
        ' to mitigate situations when the task takes too long to finish.
        t1.Wait()

        ' Construct an unstarted task
        Dim t3 As New Task(action, "gamma")

        ' Run it synchronously
        t3.RunSynchronously()

        ' Although the task was run synchrounously, it is a good practice to wait for it which observes for 
        ' exceptions potentially thrown by that task.
        t3.Wait()
    End Sub


End Module
using System;
using System.Threading;
using System.Threading.Tasks;

class StartNewDemo
{
    // Demonstrated features:
    //      Task ctor()
    //      Task.Factory
    //      Task.Wait()
    //      Task.RunSynchronously()
    // Expected results:
    //      Task t1 (alpha) is created unstarted.
    //      Task t2 (beta) is created started.
    //      Task t1's (alpha) start is held until after t2 (beta) is started.
    //      Both tasks t1 (alpha) and t2 (beta) are potentially executed on threads other than the main thread on multi-core machines.
    //      Task t3 (gamma) is executed synchronously on the main thread.
    // Documentation:
    //      https://msdn.microsoft.com/en-us/library/system.threading.tasks.task_members(VS.100).aspx
    static void Main()
    {
        Action<object> action = (object obj) =>
        {
            Console.WriteLine("Task={0}, obj={1}, Thread={2}", Task.CurrentId, obj.ToString(), Thread.CurrentThread.ManagedThreadId);
        };

        // Construct an unstarted task
        Task t1 = new Task(action, "alpha");

        // Cosntruct a started task
        Task t2 = Task.Factory.StartNew(action, "beta");

        // Block the main thread to demonstate that t2 is executing
        t2.Wait();

        // Launch t1 
        t1.Start();

        Console.WriteLine("t1 has been launched. (Main Thread={0})", Thread.CurrentThread.ManagedThreadId);

        // Wait for the task to finish.
        // You may optionally provide a timeout interval or a cancellation token
        // to mitigate situations when the task takes too long to finish.
        t1.Wait();

        // Construct an unstarted task
        Task t3 = new Task(action, "gamma");

        // Run it synchronously
        t3.RunSynchronously();

        // Although the task was run synchrounously, it is a good practice to wait for it which observes for 
        // exceptions potentially thrown by that task.
        t3.Wait();
    }


}

Exécution de code de façon asynchrone avec QueueUserWorkItem

L'exemple suivant met en file d'attente une tâche très simple représentée par la méthode ThreadProc, en utilisant la méthode QueueUserWorkItem.

Imports System
Imports System.Threading

Public Class Example
    Public Shared Sub Main()
        ' Queue the task.
        ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf ThreadProc))

        Console.WriteLine("Main thread does some work, then sleeps.")
        ' If you comment out the Sleep, the main thread exits before
        ' the thread pool task runs.  The thread pool uses background
        ' threads, which do not keep the application running.  (This
        ' is a simple example of a race condition.)
        Thread.Sleep(1000)

        Console.WriteLine("Main thread exits.")
    End Sub

    ' This thread procedure performs the task.
    Shared Sub ThreadProc(stateInfo As Object)
        ' No state object was passed to QueueUserWorkItem, so
        ' stateInfo is null.
        Console.WriteLine("Hello from the thread pool.")
    End Sub
End Class
using System;
using System.Threading;

public class Example
{
    public static void Main()
    {
        // Queue the task.
        ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc));

        Console.WriteLine("Main thread does some work, then sleeps.");
        // If you comment out the Sleep, the main thread exits before
        // the thread pool task runs.  The thread pool uses background
        // threads, which do not keep the application running.  (This
        // is a simple example of a race condition.)
        Thread.Sleep(1000);

        Console.WriteLine("Main thread exits.");
    }

    // This thread procedure performs the task.
    static void ThreadProc(Object stateInfo)
    {
        // No state object was passed to QueueUserWorkItem, so
        // stateInfo is null.
        Console.WriteLine("Hello from the thread pool.");
    }
}
using namespace System;
using namespace System::Threading;

public ref class Example
{
public:
    static void Main()
    {
        // Queue the task.
        ThreadPool::QueueUserWorkItem(gcnew WaitCallback(&ThreadProc));

        Console::WriteLine("Main thread does some work, then sleeps.");
        // If you comment out the Sleep, the main thread exits before
        // the thread pool task runs.  The thread pool uses background
        // threads, which do not keep the application running.  (This
        // is a simple example of a race condition.)
        Thread::Sleep(1000);

        Console::WriteLine("Main thread exits.");
    }

    // This thread procedure performs the task.
    static void ThreadProc(Object^ stateInfo)
    {
        // No state object was passed to QueueUserWorkItem, so
        // stateInfo is null.
        Console::WriteLine("Hello from the thread pool.");
    }
};

int main()
{
    Example::Main();
}

Indication des données de tâche pour QueueUserWorkItem

L'exemple de code suivant utilise la méthode QueueUserWorkItem pour mettre une tâche en file d'attente et fournir les données pour cette tâche.

Imports System
Imports System.Threading

' TaskInfo holds state information for a task that will be
' executed by a ThreadPool thread.
Public class TaskInfo
    ' State information for the task.  These members
    ' can be implemented as read-only properties, read/write
    ' properties with validation, and so on, as required.
    Public Boilerplate As String
    Public Value As Integer

    ' Public constructor provides an easy way to supply all
    ' the information needed for the task.
    Public Sub New(text As String, number As Integer)
        Boilerplate = text
        Value = number
    End Sub
End Class

Public Class Example
    Public Shared Sub Main()
        ' Create an object containing the information needed
        ' for the task.
        Dim ti As New TaskInfo("This report displays the number {0}.", 42)

        ' Queue the task and data.
        If ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf ThreadProc), ti) Then
            Console.WriteLine("Main thread does some work, then sleeps.")

            ' If you comment out the Sleep, the main thread exits before
            ' the ThreadPool task has a chance to run.  ThreadPool uses
            ' background threads, which do not keep the application
            ' running.  (This is a simple example of a race condition.)
            Thread.Sleep(1000)

            Console.WriteLine("Main thread exits.")
        Else
            Console.WriteLine("Unable to queue ThreadPool request.")
        End If
    End Sub

    ' The thread procedure performs the independent task, in this case
    ' formatting and printing a very simple report.
    '
    Shared Sub ThreadProc(stateInfo As Object)
        Dim ti As TaskInfo = CType(stateInfo, TaskInfo)
        Console.WriteLine(ti.Boilerplate, ti.Value)
    End Sub
End Class
using System;
using System.Threading;

// TaskInfo holds state information for a task that will be
// executed by a ThreadPool thread.
public class TaskInfo
{
    // State information for the task.  These members
    // can be implemented as read-only properties, read/write
    // properties with validation, and so on, as required.
    public string Boilerplate;
    public int Value;

    // Public constructor provides an easy way to supply all
    // the information needed for the task.
    public TaskInfo(string text, int number)
    {
        Boilerplate = text;
        Value = number;
    }
}

public class Example
{
    public static void Main()
    {
        // Create an object containing the information needed
        // for the task.
        TaskInfo ti = new TaskInfo("This report displays the number {0}.", 42);

        // Queue the task and data.
        if (ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc), ti))
        {
            Console.WriteLine("Main thread does some work, then sleeps.");

            // If you comment out the Sleep, the main thread exits before
            // the ThreadPool task has a chance to run.  ThreadPool uses
            // background threads, which do not keep the application
            // running.  (This is a simple example of a race condition.)
            Thread.Sleep(1000);

            Console.WriteLine("Main thread exits.");
        }
        else
        {
            Console.WriteLine("Unable to queue ThreadPool request.");
        }
    }

    // The thread procedure performs the independent task, in this case
    // formatting and printing a very simple report.
    //
    static void ThreadProc(Object stateInfo)
    {
        TaskInfo ti = (TaskInfo) stateInfo;
        Console.WriteLine(ti.Boilerplate, ti.Value);
    }
}
using namespace System;
using namespace System::Threading;

// TaskInfo holds state information for a task that will be
// executed by a ThreadPool thread.
public ref class TaskInfo
{
    // State information for the task.  These members
    // can be implemented as read-only properties, read/write
    // properties with validation, and so on, as required.
public:
    String^ Boilerplate;
    int Value;

    // Public constructor provides an easy way to supply all
    // the information needed for the task.
    TaskInfo(String^ text, int number)
    {
        Boilerplate = text;
        Value = number;
    }
};

public ref class Example
{
public:
    static void Main()
    {
        // Create an object containing the information needed
        // for the task.
        TaskInfo^ ti = gcnew TaskInfo("This report displays the number {0}.", 42);

        // Queue the task and data.
        if (ThreadPool::QueueUserWorkItem(gcnew WaitCallback(&ThreadProc), ti))
        {
            Console::WriteLine("Main thread does some work, then sleeps.");

            // If you comment out the Sleep, the main thread exits before
            // the ThreadPool task has a chance to run.  ThreadPool uses
            // background threads, which do not keep the application
            // running.  (This is a simple example of a race condition.)
            Thread::Sleep(1000);

            Console::WriteLine("Main thread exits.");
        }
        else
        {
            Console::WriteLine("Unable to queue ThreadPool request.");
        }
    }

    // The thread procedure performs the independent task, in this case
    // formatting and printing a very simple report.
    //
    static void ThreadProc(Object^ stateInfo)
    {
        TaskInfo^ ti = (TaskInfo^) stateInfo;
        Console::WriteLine(ti->Boilerplate, ti->Value);
    }
};

int main()
{
    Example::Main();
}

Utilisation de RegisterWaitForSingleObject

L'exemple suivant illustre plusieurs fonctionnalités de threading :

Imports System
Imports System.Threading

' TaskInfo contains data that will be passed to the callback
' method.
Public Class TaskInfo
    public Handle As RegisteredWaitHandle = Nothing
    public OtherInfo As String = "default"
End Class

Public Class Example
    Public Shared Sub Main()
        ' The main thread uses AutoResetEvent to signal the
        ' registered wait handle, which executes the callback
        ' method.
        Dim ev As New AutoResetEvent(false)

        Dim ti As New TaskInfo()
        ti.OtherInfo = "First task"
        ' The TaskInfo for the task includes the registered wait
        ' handle returned by RegisterWaitForSingleObject.  This
        ' allows the wait to be terminated when the object has
        ' been signaled once (see WaitProc).
        ti.Handle = ThreadPool.RegisterWaitForSingleObject( _
            ev, _
            New WaitOrTimerCallback(AddressOf WaitProc), _
            ti, _
            1000, _
            false _
        )

        ' The main thread waits about three seconds, to demonstrate 
        ' the time-outs on the queued task, and then signals.
        Thread.Sleep(3100)
        Console.WriteLine("Main thread signals.")
        ev.Set()

        ' The main thread sleeps, which should give the callback
        ' method time to execute.  If you comment out this line, the
        ' program usually ends before the ThreadPool thread can execute.
        Thread.Sleep(1000)
        ' If you start a thread yourself, you can wait for it to end
        ' by calling Thread.Join.  This option is not available with 
        ' thread pool threads.
    End Sub

    ' The callback method executes when the registered wait times out,
    ' or when the WaitHandle (in this case AutoResetEvent) is signaled.
    ' WaitProc unregisters the WaitHandle the first time the event is 
    ' signaled.
    Public Shared Sub WaitProc(state As Object, timedOut As Boolean)
        ' The state object must be cast to the correct type, because the
        ' signature of the WaitOrTimerCallback delegate specifies type
        ' Object.
        Dim ti As TaskInfo = CType(state, TaskInfo)

        Dim cause As String = "TIMED OUT"
        If Not timedOut Then
            cause = "SIGNALED"
            ' If the callback method executes because the WaitHandle is
            ' signaled, stop future execution of the callback method
            ' by unregistering the WaitHandle.
            If Not ti.Handle Is Nothing Then
                ti.Handle.Unregister(Nothing)
            End If
        End If 

        Console.WriteLine("WaitProc( {0} ) executes on thread {1}; cause = {2}.", _
            ti.OtherInfo, _
            Thread.CurrentThread.GetHashCode().ToString(), _
            cause _
        )
    End Sub
End Class
using System;
using System.Threading;

// TaskInfo contains data that will be passed to the callback
// method.
public class TaskInfo
{
    public RegisteredWaitHandle Handle = null;
    public string OtherInfo = "default";
}

public class Example
{
    public static void Main(string[] args)
    {
        // The main thread uses AutoResetEvent to signal the
        // registered wait handle, which executes the callback
        // method.
        AutoResetEvent ev = new AutoResetEvent(false);

        TaskInfo ti = new TaskInfo();
        ti.OtherInfo = "First task";
        // The TaskInfo for the task includes the registered wait
        // handle returned by RegisterWaitForSingleObject.  This
        // allows the wait to be terminated when the object has
        // been signaled once (see WaitProc).
        ti.Handle = ThreadPool.RegisterWaitForSingleObject(
            ev,
            new WaitOrTimerCallback(WaitProc),
            ti,
            1000,
            false );

        // The main thread waits three seconds, to demonstrate the
        // time-outs on the queued thread, and then signals.
        Thread.Sleep(3100);
        Console.WriteLine("Main thread signals.");
        ev.Set();

        // The main thread sleeps, which should give the callback
        // method time to execute.  If you comment out this line, the
        // program usually ends before the ThreadPool thread can execute.
        Thread.Sleep(1000);
        // If you start a thread yourself, you can wait for it to end
        // by calling Thread.Join.  This option is not available with
        // thread pool threads.
    }

    // The callback method executes when the registered wait times out,
    // or when the WaitHandle (in this case AutoResetEvent) is signaled.
    // WaitProc unregisters the WaitHandle the first time the event is
    // signaled.
    public static void WaitProc(object state, bool timedOut)
    {
        // The state object must be cast to the correct type, because the
        // signature of the WaitOrTimerCallback delegate specifies type
        // Object.
        TaskInfo ti = (TaskInfo) state;

        string cause = "TIMED OUT";
        if (!timedOut)
        {
            cause = "SIGNALED";
            // If the callback method executes because the WaitHandle is
            // signaled, stop future execution of the callback method
            // by unregistering the WaitHandle.
            if (ti.Handle != null)
                ti.Handle.Unregister(null);
        }

        Console.WriteLine("WaitProc( {0} ) executes on thread {1}; cause = {2}.",
            ti.OtherInfo,
            Thread.CurrentThread.GetHashCode().ToString(),
            cause
        );
    }
}
using namespace System;
using namespace System::Threading;

// TaskInfo contains data that will be passed to the callback
// method.
public ref class TaskInfo
{
public:
    static RegisteredWaitHandle^ Handle = nullptr;
    static String^ OtherInfo = "default";
};

public ref class Example
{
public:
    static void Main()
    {
        // The main thread uses AutoResetEvent to signal the
        // registered wait handle, which executes the callback
        // method.
        AutoResetEvent^ ev = gcnew AutoResetEvent(false);

        TaskInfo^ ti = gcnew TaskInfo();
        ti->OtherInfo = "First task";
        // The TaskInfo for the task includes the registered wait
        // handle returned by RegisterWaitForSingleObject.  This
        // allows the wait to be terminated when the object has
        // been signaled once (see WaitProc).
        ti->Handle = ThreadPool::RegisterWaitForSingleObject(
            ev,
            gcnew WaitOrTimerCallback(&WaitProc),
            ti,
            1000,
            false );

        // The main thread waits three seconds, to demonstrate the
        // time-outs on the queued thread, and then signals.
        Thread::Sleep(3100);
        Console::WriteLine("Main thread signals.");
        ev->Set();

        // The main thread sleeps, which should give the callback
        // method time to execute.  If you comment out this line, the
        // program usually ends before the ThreadPool thread can execute.
        Thread::Sleep(1000);
        // If you start a thread yourself, you can wait for it to end
        // by calling Thread.Join.  This option is not available with
        // thread pool threads.
    }

    // The callback method executes when the registered wait times out,
    // or when the WaitHandle (in this case AutoResetEvent) is signaled.
    // WaitProc unregisters the WaitHandle the first time the event is
    // signaled.
    static void WaitProc(Object^ state, bool timedOut)
    {
        // The state object must be cast to the correct type, because the
        // signature of the WaitOrTimerCallback delegate specifies type
        // Object.
        TaskInfo^ ti = (TaskInfo^) state;

        String^ cause = "TIMED OUT";
        if (!timedOut)
        {
            cause = "SIGNALED";
            // If the callback method executes because the WaitHandle is
            // signaled, stop future execution of the callback method
            // by unregistering the WaitHandle.
            if (ti->Handle != nullptr)
                ti->Handle->Unregister(nullptr);
        }

        Console::WriteLine("WaitProc( {0} ) executes on thread {1}; cause = {2}.",
            ti->OtherInfo,
            Thread::CurrentThread->GetHashCode().ToString(),
            cause
        );
    }
};

int main()
{
    Example::Main();
}

Voir aussi

Tâches

Comment : retourner une valeur à partir d'une tâche

Référence

ThreadPool

Task

Task<TResult>

Concepts

Bibliothèque parallèle de tâches

Bibliothèque parallèle de tâches

Threads et threading

E/S sur fichier asynchrones

minuteries (Timers)

Autres ressources

Fonctionnalités et objets de threading

Historique des modifications

Date

Historique

Motif

Septembre 2010

La taille par défaut et les informations obsolètes sur la création de nouveaux threads ont été corrigées. Un exemple a été ajouté à partir de Bibliothèque parallèle de tâches.

Résolution des bogues de contenu.