2017-10-10 6 views
1

私は、一連のタスクを順番に実行する一種のスケジューラ(関連する用語ではないかもしれません)を構築しようとしています。ここで C#6はタスクとすべてのサブタスクの完全な完了を待っています

は(悪いキュー/デキューメカニズムを無視するが、ここでは問題ないが、私は推測してください)私のPOCコードです

EDIT:@Theraot

static void Main(string[] args) 
    { 
     ProcessingQueue o_q = new ProcessingQueue(); 
     o_q.Enqueue(async() => { await SimulateTaskSequence(1); }); 
     o_q.Enqueue(async() => { await SimulateTaskSequence(2); }); 

     Console.ReadLine(); 
    } 

    public static async Task SimulateTaskSequence(int taskNbr) 
    { 
     Console.WriteLine("T{0} - Working 1sec", taskNbr); 
     Thread.Sleep(1000); 

     Console.WriteLine("T{0} - Zzz 1st 1sec", taskNbr); 
     await Task.Delay(1000); 

     Console.WriteLine("T{0} - Working 1sec", taskNbr); 
     Thread.Sleep(1000); 

     Console.WriteLine("T{0} - Done", taskNbr); 
    } 

    public class ProcessingQueue 
    { 
     Queue<Action> _Queue = new Queue<Action>(); 
     private bool _stillRunning = false; 

     public void Enqueue(Action a) 
     { 
      lock (_Queue) 
      { 
       _Queue.Enqueue(a); 

       if (_stillRunning == false) 
       { 
        StartProcessing(); 
       } 
      } 
     } 


     private void StartProcessing() 
     { 
      _stillRunning = true; 

      Task.Run(async() => 
      { 
       Action a = null; 

       while (true) 
       { 
        lock (_Queue) 
        { 
         if (_Queue.Any() == true) 
         { 
          a = _Queue.Dequeue(); 
         } 
         else 
         { 
          break; 
         } 
        } 

        await Task.Run(a); //how to wait for all subtasks!!??? 
       } 
       _stillRunning = false; 
      }); 
     } 

私の問題の助けのおかげで第1のタスク(T1)を待つとすぐに、第2のタスク(T2)が実行され始める。

T1 - Working 1sec 
T1 - Zzz 1st 1sec 
T2 - Working 1sec 
T2 - Zzz 1st 1sec 
T1 - Working 1sec 
T1 - Done 
T2 - Working 1sec 
T2 - Done 

しかし、私は期待していことは、次のようになります:私は次の出力を得る

T1 - Working 1sec 
T1 - Zzz 1st 1sec 
T1 - Working 1sec 
T1 - Done 
T2 - Working 1sec 
T2 - Zzz 1st 1sec 
T2 - Working 1sec 
T2 - Done 

を、これはデフォルトの動作である理由私は理解し、私はそれを変更する必要があります。私は新しいTaskFactoryでTaskContinuationOptionsとTaskCreationOptionsの周りを遊んでいたが、良い結果は得られなかった。 それも可能ですか?

どうもありがとう クリストフ

+0

ProcessingQueueクラスは、すでにフレームワークに存在し、ThreadPoolです。正しく置き換えにくく、ThreadPoolがしないことは何もしません。待ち望まれていたこと以外はすぐに間違っていました。それをしないでください。 –

+0

@HansPassant OPが望むのは、OPが追加されたタスクを順番に完了させたいという点でThreadPoolとは異なります。 ThreadPoolには、そのような保証はありません。実際、ThreadPoolのアイデアは、複数のスレッドを使用して並列に物事を実行することです(もちろん、スレッドを再編集します)。さて、これは、これらのタスクを同期的に実行することによって、または待機のためにスレッドを使用する他の手段によって達成できます... OPは、そのいずれも望んでいません。 – Theraot

+0

タスククラスは非常によく似ています。メインタスクをシーケンスするためにContinueWith、サブタスク補完を待つWaitAllだけが必要です。簡単なピーシーですが、あなた自身のスレッドプールを作成すると、それはちょっと見づらくなります。 –

答えて

2

私の代わりに質問に書かれたコードでProcessingQueue<Action>

public class ProcessingQueue 
{ 
    Queue<Func<Task>> _Queue = new Queue<Func<Task>>(); 

    private bool _stillRunning = false; 

    public void Enqueue(Func<Task> a) 
    { 
     lock (_Queue) 
     { 
      _Queue.Enqueue(a); 

      if (_stillRunning == false) 
      { 
       StartProcessing(); 
      } 
     } 
    } 

    private void StartProcessing() 
    { 
     _stillRunning = true; 

     Task.Run(async() => 
     { 
      Func<Task> a = null; 

      while (true) 
      { 
       lock (_Queue) 
       { 
        if (_Queue.Any() == true) 
        { 
         a = _Queue.Dequeue(); 
        } 
        else 
        { 
         break; 
        } 
       } 

       await a(); //how to wait for all subtasks!!??? 
      } 
      _stillRunning = false; 
     }); 
    } 

説明

Action a; 
... 
await Task.Run(a); 
ProcessingQueue<Func<Task>>を作成することをお勧め

アクションが非同期タスクを含む可能性があるため、Runメソッドはタスクが存在しないため、タスクを待機していないため、Task.Run(Action action)を実行しています。 Task.Run(Func<Task> task)と呼ぶと、Runメソッドはそれがタスクであることを知り、それが待ち受けるでしょう。

+0

@Theraotが指摘してくれてありがとう –

関連する問題