2017-05-30 92 views
1

我在c#中有一些工作管理器,它將接收任務並執行它們。任務將從不同的線程到達,但它們必須按照它們接收的順序同時執行一個。 我不想要一個while循環,它將一直運行,檢查它們是否是隊列中的新任務。是否有內置隊列或簡單的方法來實現隊列,該隊列將等待任務並同步執行而不需要等待?帶任務的線程安全隊列

+0

我不認爲這是建立功能對於此模式,但你可以通過建立一個無while循環** ** SemaphoreSlim –

+0

你檢查[ConcurrentQueue ](https://msdn.microsoft.com/ en-us/library/dd267265(v = vs.110).aspx)和/或[Queue.Synchronized](https://msdn.microsoft.com/en-us/library/system.collections.queue.synchronized( v = vs.110)的.aspx)? – Hintham

+1

考慮到您的要求,它不會一直運行,TPL數據流是一種可行的方法。你可以控制它的執行方式(就線程而言),所以我認爲你應該能夠確保一次只運行一個。小心你不要創建積壓。 – john

回答

0

按照該意見,你應該考慮ConcurrentQueueBlockingCollection和使用GetConsumingEnumerable(),而不是你不想要的WHILE循環

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

_collection.Add() can be called from multiple threads 

在一個單獨的線程可以使用

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

請求是在同一時間做一個 –

+0

他的判決不明確,「但他們必須同時執行一個」。我假設他希望他們以順序方式一次執行一個 –

+0

「但它們必須同時執行**只有一個**」 –

0

你可以使用SemaphoreSlim(https://msdn.microsoft.com/en-us/library/system.threading.semaphoreslim(v=vs.110).aspx)和ConcurrentQueue

示例:

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

謝謝。這看起來像一個很好的解決方案,但BlockingCollection對於這個問題似乎更簡單和簡單。 – user3126358