2016-08-04 3 views
0

背景

私は現在、およびではなく、端末インターフェイスを介して動作するGUIを使用して、何かの機能を再現しています。したがって、元のGUI形式で動作するため、エラーはイベントのトリガーとは反対側にはありません。非同期イベントによるスレッドブロックとブロック解除を管理するにはどうすればよいですか?

複数のマシンでサブタスクで構成されるタスクを実行します。

私は、進行が行われたときにトリガーとなるイベントに登録し、説明的なメッセージを出力します。 すべてのYマシンのXサブタスクごとにメッセージが出力されます。

非同期マルチスレッド処理が実行されます。

解決される各マシンのサブタスクごとに1回だけメッセージを出力したいと思います。

私はサブタスクの完了を追跡し、ローがマシンとカラムのサブタスクである2Dブール配列を維持します。

問題

デバッグするとき、私は以下のイベントハンドラメソッドが入力されていることがわかります。 numOfSubtasksFoundEventHandlerのprintステートメントが実行されますが、AutoResetイベントを設定するために到達する前に、複数のBigTaskイベントがトリガーされ、.WaitOneでブロックされます。

numOfSubtasksFound.Set()が後で実行されるにもかかわらず、何も印刷されず、プログラムが実行を終了しません。何もnumOfSubtasksFound.WaitOneを通過しません。

BigTaskHandlerメソッドのnumOfSubtasksFound.WaitOneを取り出すと、同様の動作が発生しますが、BigTaskが完了したことを示すメッセージがいくつか表示され、プログラムが別の場所で停止します。

ここでブロックとブロック解除を管理する最善の方法は何ですか?また、小さな修正はありますか?私は必要なもの

ゴール

はnumOfSubtasksFoundEventHandlerが一度実行されるまでサブタスクのイベントハンドラメソッドの動作をブロックする方法です。一度だけ実行するにはnumOfSubTasksFoundEventHandlerが必要です。

現在、サブタスクイベントハンドラは適切にアンブロックされていません。スイッチケースコードは、numOfSubtasksFound.Set()の後に決して実行されません。実行されます。

//MAIN 
    bool[] machinesDoneTasks = new bool[numOfMachines]; 
    bool[][] machinesDoneSubtasks = new bool[numOfMachines][]; 

    try 
    { 
     //thread/task blocking 
     numOfSubtasksFound = new AutoResetEvent(false); 
     AllSubTasksDone = new AutoResetEvent(false); 
     AllBigTasksDone = new AutoResetEvent(false); 

     //Subscribe to events to get number of subtasks and print useful information as tasks progress 
     numOfSubtasksFoundEvent += numOfSubtasksFoundEventHandler; 
     SubTaskProgEvent += SubTaskEventProgHandler; //prog stands for progress 
     BigTaskProgEvent += BigTaskProgEventHandler; 

     RunAllTasksOnAllMachines();//this will trigger the events above 

     //Don't exit program until those descriptive messages have been printed 
     numOfSubtasksFound.WaitOne(); 
     AllSubTasksDone.WaitOne(); 
     //SubTaskProgEvent -= SubTaskProgEventHandler; 
     AllBigTasksDone.WaitOne(); 
     //BigTaskProgEvent -= BigTaskProgEventHandler; 
    } 
    catch (Exception e) 
    { 
     //print exceptions 
    } 
    //END MAIN 

以下は必ずしもトリガーされる最初のイベントではありません。

internal void numOfSubtasksFoundEventHandler(object sender, EventArgs e) 
{ 
    //get number of subtasks from args after checking for nulls, empty arrays 

    for (int i = 0; i < numOfSubtasks; i++) 
     machinesDoneSubtasks[i] = new bool[numOfSubtasks]; 

    Console.WriteLine("number of subtasks found"); 
    numOfSubtasksFoundEvent -= numOfSubtasksFoundEventHandler;//don't subscribe to event where we get this from anymore 

    if (numOfSubtasksFound != null) 
     numOfSubtasksFound.Set(); //stop blocking 
} 

サブタスクイベントは、大きなタスクイベントの前に必ずしも処理されるとは限りません。

internal void SubtaskEventProgHandler(object sender, EventArgs e) 
{ 
    //null, empty checks on args 

    //Wait until we know how many subtasks there are and the 2D boolean array is fully built 
    numOfSubtasksFound.WaitOne(); 

    switch (e.WhatHappened) 
    { 
     Case.TaskComplete: 

      Console.Write(e.Machine + " is done subtask " + e.subTask); 

      //logic to determine machine and subtask 
      machinesDoneSubtasks[machine][Subtask] = true; 

      if (AllSubTasksDone != null && machinesDoneSubtasks.OfType<bool>().All(x => x)) 
       AllSubTasksDone.Set(); //stop blocking when 2D array is all true 

      break; 
      //other cases, different prints, but same idea 
    }  
} 

BigTask進捗イベントは、処理の始めと終わりに発生します。私は、私が望むケースの詳細だけを印刷します。

internal void BigTaskProgEventHandler(object sender, EventArgs e) 
{ 
    //Wait until we know how many subtasks there are and the 2D boolean array is fully built before printing 
    numOfSubtasksFound.WaitOne(); 

    //null, empty exception checks 
    switch (e.WhatHappened) 
    { 
      Case.TaskComplete: 

      Console.Write(e.Machine + " is done task " + e.subTask); 

    //logic to determine machine 
    machinesDoneTasks[machine] = true; 

    if (AllBigTasksDone != null && machinesDoneTasks.All(x => x)) 
     AllBigTasksDone.Set(); 

    break; 
    } 
    //other cases, different prints, but same idea 
} 
+0

.Netで非同期操作を管理する最善の方法は、async/awaitを使用することです。あなたの必要条件は何ですか?あなたが解決しようとしている問題は何ですか? – radianz

+1

'RunAllTask​​sOnAllMachines'のコードを投稿できますか?また、あなたの質問を減らすことができますか?私たちは、「非同期のマルチスレッド化のシナリオが続く」というような行は必要ありません。そして、私は "非GUIインタフェースを介して"何を理解していない。と "イベントのトリガーと他の終わり。手段。あなたが書いたものをもう一度読んで理解できるかどうかを確認する必要があります。 – Enigmativity

+0

@RobertoBastianicは、より明確になるように説明を更新しました。上記のように、私がリストしていないものはすべて正常に動作します。 質問を明確にするために質問を更新します。 – despair

答えて

0

私の問題は、第一イベントがトリガされた後、他のサブタスクのイベントハンドラのイベントがブロックされる.WaitOneを呼ぶだろうということでした。これは、サブタスクの数が発見された後に発生する可能性があります。この問題は、.Setは一度だけ呼び出され、ブロックされないことになりました。

サブタスクの数が検出されたときにブール値フラグを設定し、サブタスクイベントハンドラをロックする方法がありました。

0

async/awaitモデルの例。 各マシンで多数のタスクが実行され、値が計算されます。 すべてのタスクが完了すると、値がコンソールに表示されます。

static void Main(string[] args) 
     { 
      var service = new DispatchTasksOnMachinesService(8, 3); 
      service.DispatchTasks(); 
      Console.Read(); 
     } 

     class DispatchTasksOnMachinesService 
     { 
      int numOfMachines; 
      int tasksPerMachine; 
      [ThreadStatic] 
      private Random random = new Random(); 

      public DispatchTasksOnMachinesService(int numOfMachines, int tasksPerMachine) 
      { 
       this.numOfMachines = numOfMachines; 
       this.tasksPerMachine = tasksPerMachine; 
      } 

      public async void DispatchTasks() 
      { 
       var tasks = new List<Task<Tuple<Guid, Machine, int>>>(); 
       for (int i = 0; i < this.numOfMachines; i++) 
       { 
        var j = i; 
        for (int k = 0; k < this.tasksPerMachine; k++) 
        { 
         var task = Task.Run(() => Foo(Guid.NewGuid(), new Machine("machine" + j))); 
         tasks.Add(task); 
        } 
       } 

       var results = await Task.WhenAll<Tuple<Guid, Machine, int>>(tasks); 
       foreach (var result in results) 
       { 
        Console.WriteLine($"Task {result.Item1} on {result.Item2} yielded result {result.Item3}"); 
       } 
      } 

      private Tuple<Guid, Machine, int> Foo(Guid taskId, Machine machine) 
      { 
       Thread.Sleep(TimeSpan.FromSeconds(random.Next(1,5))); 
       Console.WriteLine($"Task {taskId} has completed on {machine}"); 
       return new Tuple<Guid, Machine, int>(taskId, machine, random.Next(500, 2000)); 
      } 
     } 

     class Machine 
     { 
      public string Name { get; private set; } 

      public Machine(string name) 
      { 
       this.Name = name; 
      } 

      public override string ToString() 
      { 
       return this.Name; 
      } 
     } 
関連する問題