using System;
using System.Threading;
using Developpez.Dotnet.Properties;
namespace Developpez.Dotnet.Threading
{
///
/// Utilitaires d'exécutions de méthodes via différents threads
///
public static class ThreadUtils
{
static bool _useThreadPool = true;
///
/// Indique si par défaut le ThreadPool doit être utilisé à la place
/// de créer un nouveau thread pour les opérations compatibles
///
public static bool UseThreadPool
{
get {return _useThreadPool;}
set{_useThreadPool = value;}
}
///
/// Exécute le délégué spécifié en arrière plan dans un nouveau thread
///
/// Délégué à exécuter en arrière plan
public static void ExecuteBackground(ThreadStart method)
{
ExecuteBackground(method, "Thread de travail en arrière plan");
}
///
/// Exécute le délégué spécifié en arrière plan dans un nouveau thread
///
/// Délégué à exécuter en arrière plan
/// Description du thread crée
public static void ExecuteBackground(ThreadStart method, string description)
{
Thread m_thread = new Thread(method);
m_thread.Priority = ThreadPriority.BelowNormal;
m_thread.IsBackground = true;
m_thread.Name = description;
m_thread.Start();
}
///
/// Exécute une méthode avec un temps maximal d'exécution. Si le temps d'exécution est dépassé
/// et que le délégué ne s'est toujours pas terminé, le travail est arrêté via Thread.Abort
/// et une exception TimeoutException est levée
///
/// Délégué à exécuter
/// Temps maximal d'exécution du délégué
public static void Execute(ThreadStart method, TimeSpan timeout)
{
Execute(method, "Thread de travail asyncrone", timeout);
}
///
/// Exécute une méthode avec un temps maximal d'exécution. Si le temps d'exécution est dépassé
/// et que le délégué ne s'est toujours pas terminé, le travail est arrêté via Thread.Abort
/// et une exception TimeoutException est levée
///
/// Délégué à exécuter
/// Description du thread crée (si un thread est crée)
/// Temps maximal d'exécution du délégué
public static void Execute(ThreadStart method, string description, TimeSpan timeout)
{
if (method == null)
throw new ArgumentNullException("method");
if (timeout.TotalMilliseconds < 1)
throw new ArgumentOutOfRangeException(ExceptionMessages.TimeoutOutOfRange);
if (timeout.TotalMilliseconds >= int.MaxValue)
{
/* temps infini */
method.Invoke();
return;
}
Thread m_thread = new Thread(method);
m_thread.Name = description;
m_thread.Start();
DateTime begin = DateTime.Now;
while (true)
{
switch (m_thread.ThreadState)
{
case ThreadState.Aborted:
case ThreadState.AbortRequested:
case ThreadState.Stopped:
case ThreadState.StopRequested:
{
return;
}
default:
{
break;
}
}
if ((DateTime.Now - begin) > timeout)
{
m_thread.Abort();
throw new TimeoutException(ExceptionMessages.OperationTimedOut);
}
Thread.Sleep(10); /* pour épargner du CPU */
}
}
///
/// Exécute un délégué de manière asynchrone
///
/// Délégué à exécuter
public static void ExecuteAsync(ThreadStart method)
{
ExecuteAsync(method, "Thread de travail asynchrone");
}
///
/// Exécute un délégué de manière asynchrone
///
/// Délégué à exécuter
/// Si un thread est crée, description de celui ci
public static void ExecuteAsync(ThreadStart method, string description)
{
if (method == null)
throw new ArgumentNullException("method");
if (UseThreadPool)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(delegate
{
method.Invoke();
}));
}
else
{
Thread m_thread = new Thread(method);
m_thread.Name = description;
m_thread.Start();
}
}
///
/// Exécute un délégué de manière asynchrone
///
/// Délégué à exécuter
/// Evènement à appeler lorsque l'opération est terminée
///
/// onFinish peut être null cependant si onFinish est différent de null il est exécuté
/// sur le thread ayant exécuté le travail, pas sur le thread appelant
///
public static void ExecuteAsync(ThreadStart method, EventHandler onFinish)
{
ExecuteAsync(method, "Thread de travail asyncrone", onFinish);
}
///
/// Exécute un délégué de manière asynchrone
///
/// Délégué à exécuter
/// Description du thread crée (si un thread est crée)
/// Evènement à appeler lorsque l'opération est terminée
///
/// onFinish peut être null cependant si onFinish est différent de null il est exécuté
/// sur le thread ayant exécuté le travail, pas sur le thread appelant
///
public static void ExecuteAsync(ThreadStart method, string description, EventHandler onFinish)
{
if (method == null)
throw new ArgumentNullException("method");
if (onFinish == null)
ExecuteAsync(method, description);
else
{
ExecuteAsync(new ThreadStart(delegate
{
method.Invoke();
onFinish.Invoke(null, EventArgs.Empty);
}), description);
}
}
}
}