2011-06-24 22 views
4

タスクを順番に実行するようにスケジュールする方法を見つけようとしています。私がこれまでに出てきた解決策は以下に掲載されていますが、私はそれがはるかに簡単で効率的な方法で行うことができるという疑いがあります。C#タスクをシーケンスで実行する効率的な方法

public class SequentialTaskRunner 
{ 
    private ISet<Task> runningTasks = new HashSet<Task>(); 

    public void Run(Task task) 
    { 
     lock (runningTasks) 
     { 
      var tasksToAwait = runningTasks.ToArray(); 

      // create a task that waits for the currently running tasks 
      var waitingTask = Task.Factory.StartNew(() => 
      { 
       Task.WaitAll(tasksToAwait); 
      }); 

      // make sure the task gets removed from the running tasks on completion 
      task.ContinueWith((antecedent2) => 
      { 
       lock (runningTasks) 
       { 
        runningTasks.Remove(task); 
       } 
      }); 

      // prepend the waiting task 
      waitingTask.ContinueWith((antecedent) => task.Start()); 

      runningTasks.Add(task); 
     } 
    } 
} 

私はこれを使用して、COMポート接続を処理するエンキュータスクに使用して、互いのやり取りを防止します。

状況は次のとおりです。私はrfidデバイスで作業しています。プレイには2人のドライバーがいます。 1である。要求されたときに利用可能なcomポートをスキャンして(他の)リーダーを見つけるもう1つの方法。場合によっては、リーダースキャンを使用してポートスキャンを行い、接続を復元することがあります。これはまさに私が共起したくない2つの「ポートスキャン」タスクです。

これは、2つのタスクを同時に実行したくないという状況にどのようになったのかを明確にしたいと考えています。さて、この質問に答えることを避ける別の方法があるかもしれません。しかし、私はまだあなたならば良い解決策は、C#4の上に、あなたがあなたのキューの

またはC4で見て、他の同時*クラスを持つスレッドセーフであるConcurrentQueueクラスができた:)

+0

したがって、タスクを同期して実行したいですか?どのようにあなたはこの場所にあなた自身を得ましたか?あなたは取り返して、アクションだけを使うことができますか? – Will

+0

それは良い質問です。私は少しこれについて詳しく説明するために投稿を編集します。 – bvh

答えて

4

(全体の前投稿はコメントあたり)です。

私には、3種類のタスクがあります。あなたはこれら三つができるだけ平行になりたいが、それはそうにジャンプすることを選択した場合は、リーダーをもたい

  1. リーダー
  2. ライター
  3. ポートスキャナ

Port Scannerが稼動している間は再スキャンを行わないようにポートスキャン再接続に切り替えます。この状況に取り組む1つの方法はSemaphoreです。セマフォは、限られた数のリソースへのアクセスを制御します。

あなたの場合、限られた数のリソース(実際にはわずか1)しか利用できません(「ポートスキャン」)。この場合、より単純なものを使用することができますAutoResetEvent。しかし、私はSemaphoreが実際に混乱を減らすかもしれないと感じます。

// Only 1 task may port scan at a time 
Semaphore portScanResource = new Semaphore(initialCount: 1, maximumCount: 1); 

// ... 

// "Reader task" 
var task = Task.Factory.StartNew(() => 
    { 
     // ... 
     if (shouldPortScan) 
     { 
      portScanResource.WaitOne(); 
      try 
      { 
       // do your port scan 
      } 
      finally 
      { 
       // we're done 
       portScanResource.Release(); 
      } 
     } 
    }); 

ポートスキャナタスクは1つだけのスレッドが一度にポートスキャンを実行確保し、同じSemaphoreを使用します。

+0

私がそれをよく理解していれば、ConcurrentBagは 'runningTasks'から 'task'を取り下げることができません。私は現在、ConcurrentQueueが@anvarbekとして提案されているかどうかを調べています。なぜなら、「仕上げ作業」は常にデキューする必要があるからです。 – bvh

+0

@bvh:これで編集がより明確になります。私はこれを迷っている。より良い解決策が見つからない場合は、この回答を削除します。 – user7116

+0

nice。私の例のコードを見ると、私はメソッド名 'Run'がちょっと混乱していることがわかります。代わりに「エンキュー」または「スケジュール」があります。これらの後者は、スケジューラを作ることも興味深い選択肢であることを示唆しています。 – bvh

0

どうなるか非常に興味。パラレルエクステンションも非常に便利ですが、yyはそれをyrの必要性に合わせて調整する必要があります

関連する問題