2017-05-30 1 views
1

J'ai une sorte de gestionnaire de travail dans C# qui recevra des tâches à faire et il va les exécuter. La tâche arrivera de différents threads, mais ils doivent être exécutés seulement un en même temps dans l'ordre où ils ont été reçus. Je ne veux pas de boucle while, qui sera exécutée tout le temps, en vérifiant s'il s'agit de nouvelles tâches dans la file d'attente. Y a-t-il une file d'attente intégrée ou un moyen facile d'implémenter une file d'attente qui attendra les tâches et les exécutera de façon synchrone sans attendre?File d'attente thread-safe avec des tâches

+0

Je ne pense pas qu'il y ait construire fonctionnalité pour ce modèle mais vous pouvez construire un sans en boucle à travers ** SemaphoreSlim ** –

+0

Avez-vous vérifié [ConcurrentQueue ] (https://msdn.microsoft.com/ fr-fr/library/dd267265 (v = vs.110) .aspx) et/ou [Queue.Synchronized] (https://msdn.microsoft.com/fr-fr/library/system.collections.queue.synchronized (v = vs.110) .aspx)? – Hintham

+1

TPL Dataflow est une solution, compte tenu de votre exigence selon laquelle il ne fonctionne pas tout le temps. Vous pouvez contrôler comment il est exécuté (en termes de threads, etc.), donc je pense que vous devriez être en mesure de vous assurer qu'un seul s'exécute à la fois. Attention, vous ne créez pas de backlog cependant. – john

Répondre

0

Selon les commentaires que vous devriez regarder dans ConcurrentQueue mais aussi BlockingCollection et utiliser GetConsumingEnumerable() au lieu de la boucle indésirable while

BlockingCollection<YourClass> _collection = 
      new BlockingCollection<YourClass>(new ConcurrentQueue<YourClass>()); 

_collection.Add() can be called from multiple threads 

sur un thread séparé, vous pouvez utiliser

foreach (var message in _collection.GetConsumingEnumerable()) 
{} 
+0

La demande est de le faire en même temps –

+0

Sa phrase n'est pas claire "mais ils ne doivent être exécutés qu'un seul à la fois". Je suppose qu'il veut qu'ils soient exécutés un à la fois d'une manière séquentielle –

+0

"mais ils doivent être exécutés ** un seul ** en même temps" –

0

Vous pouvez utilisez un SemaphoreSlim (https://msdn.microsoft.com/en-us/library/system.threading.semaphoreslim(v=vs.110).aspx) et une queue concurrente

Exemple:

private delegate void TaskBody(); 

    private class TaskManager 
    { 
     private ConcurrentQueue<TaskBody> 
      TaskBodyQueue = new ConcurrentQueue<TaskBody>(); 

     private readonly SemaphoreSlim 
      TaskBodySemaphoreSlim = new SemaphoreSlim(1, 1); 

     public async void Enqueue(TaskBody body) 
     { 
      TaskBodyQueue.Enqueue(body); 

      await TaskBodySemaphoreSlim.WaitAsync(); 

      Console.WriteLine($"Cycle ..."); 

      if (TaskBodyQueue.TryDequeue(out body) == false) { 
       throw new InvalidProgramException($"TaskBodyQueue is empty!"); 
      } 

      body(); 

      Console.WriteLine($"Cycle ... done ({TaskBodyQueue.Count} left)"); 

      TaskBodySemaphoreSlim.Release(); 
     } 
    } 

    public static void Main(string[] args) 
    { 
     var random = new Random(); 
     var tm = new TaskManager(); 

     Parallel.ForEach(Enumerable.Range(0, 30), async number => { 
      await Task.Delay(100 * number); 

      tm.Enqueue(delegate { 
       Console.WriteLine($"Print {number}"); 
      }); 
     }); 

     Task 
      .Delay(4000) 
      .Wait(); 

     WaitFor(action: "exit"); 
    } 

    public static void WaitFor(ConsoleKey consoleKey = ConsoleKey.Escape, string action = "continue") 
    { 
     Console.Write($"Press {consoleKey} to {action} ..."); 

     var consoleKeyInfo = default(ConsoleKeyInfo); 

     do { 
      consoleKeyInfo = Console.ReadKey(true); 
     } 
     while (Equals(consoleKeyInfo.Key, consoleKey) == false); 

     Console.WriteLine(); 
    } 
+0

Merci. Cela ressemble à une bonne solution, mais BlockingCollection semble être plus facile et plus simple pour ce problème. – user3126358