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.
Remarque |
---|
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.
Remarque |
---|
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.
Remarque |
---|
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.
Remarque |
---|
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.
Attention |
---|
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 :
Mise en file d'attente une tâche pour son exécution par les threads ThreadPool, avec la méthode RegisterWaitForSingleObject.
Signalisation d'une tâche à exécuter, avec AutoResetEvent. Consultez EventWaitHandle, AutoResetEvent, CountdownEvent et ManualResetEvent.
Gestion des délais et des signaux avec un délégué WaitOrTimerCallback.
Annulation d'une tâche mise en file d'attente avec RegisteredWaitHandle.
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
Concepts
Bibliothèque parallèle de tâches
Bibliothèque parallèle de tâches
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. |