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); } } } }