2017-09-26 7 views
0

一度に実行されるmax 2と並行して5つのタスクを完了する必要があります。 したがって、タスクが完了するとすぐに、未処理のタスクがなくなるまで次のタスクを実行する必要があります。Task.Factory.StartNewのランダムタスクは起動しません

私はsolution by L.B.を使用しています。これには、タスク間の同期にセマフォを使用することが含まれます。

void LaunchTaskPool() 
    { 
     SemaphoreSlim maxThreadSemaphore = new SemaphoreSlim(2); //Max 2 tasks at a time. 

     for (int i = 0; i < 5; i++)      //loop through 5 tasks to be assigned 
     { 
      maxThreadSemaphore.Wait();     //Wait for the queue 

      Console.WriteLine("Assigning work {0} ", i); 

      Task t = Task.Factory.StartNew(() => 
      { 
       DoWork(i.ToString());     // assign tasks 
      }, TaskCreationOptions.LongRunning 
       ) 
       .ContinueWith(
       (task) => maxThreadSemaphore.Release() // step out of the queue 
       ); 
     } 

    } 

    void DoWork(string workname) 
    { 
     Thread.Sleep(100); 
     Console.WriteLine("--work {0} starts", workname); 
     Thread.Sleep(1000); 
     Console.WriteLine("--work {0} finishes", workname); 

    } 

問題は、いくつかのランダムなタスクも開始されないということです。ここで例えば、1と3が起動したことがない作業と4が二回実行してしまった作業:

Output

hereが提案し、それは助けにはならなかったように私はTask.WaitAll()を追加してみました。

ご協力いただきありがとうございます。

コンスタンチン。

+0

https://blogs.msdn.microsoft.com/ericlippert/2009/11/12/closing-over-the-loop -variable-considered-harmful/ –

答えて

5

代わりにParallel.For()を使用することをお勧めします。ホイールを再発明する必要はありません! Parallel.For()を使用するときは、MaxDegreeOfParallelismを指定することができます。

例えば:

using System; 
using System.Threading; 
using System.Threading.Tasks; 

namespace ConsoleApp4 
{ 
    class Program 
    { 
     static void Main() 
     { 
      Parallel.For(
       0, // Inclusive start 
       5, // Exclusive end 
       new ParallelOptions{MaxDegreeOfParallelism = 2}, 
       i => DoWork(i.ToString())); 
     } 

     static void DoWork(string workname) 
     { 
      Thread.Sleep(100); 
      Console.WriteLine("--work {0} starts", workname); 
      Thread.Sleep(1000); 
      Console.WriteLine("--work {0} finishes", workname); 

     } 
    } 
} 

は、(実際に、私はちょうど見て、これはあなたがリンクされ、スレッド内の他の答えの一つに既にある - あなたはdidnの理由がありますのコピーを作成し、これを修正するには

You are accessing a "modified closure" in the loop.:「tはあなたの実際の質問に答えるためにとにかく)...私たちは重複としてこの質問を閉じる必要がありますね、

をそのソリューションを使用する場合ではありません?ループ変数iタスクに渡す前に:

SemaphoreSlim maxThreadSemaphore = new SemaphoreSlim(2); //Max 2 tasks at a time. 

for (int i = 0; i < 5; i++)      //loop through 5 tasks to be assigned 
{ 
    maxThreadSemaphore.Wait();     //Wait for the queue 

    Console.WriteLine("Assigning work {0} ", i); 
    int copy = i; // <----- Make a copy here. 

    Task t = Task.Factory.StartNew(() => 
      { 
       DoWork(copy.ToString());     // assign tasks 
      }, TaskCreationOptions.LongRunning 
     ) 
     .ContinueWith(
      (task) => maxThreadSemaphore.Release() // step out of the queue 
     ); 
} 
+0

解決方法と変更されたクロージャに関するリンクについてMatthewに感謝します – BusinessAlchemist

1

問題をあなたの解決策とTaskが開始される前に、ループが出回って実行され、次のTaskを開始していることです。

@Matthew Watsonは、Parallel.Forをお勧めします。

これはあなたの問題を解決するだけで関心のうち

static void LaunchTaskPool() 
{ 
    SemaphoreSlim maxThreadSemaphore = new SemaphoreSlim(2); //Max 2 tasks at a time. 

    for (int i = 0; i < 5; i++)      //loop through 5 tasks to be assigned 
    { 
     maxThreadSemaphore.Wait();     //Wait for the queue 

     Console.WriteLine("Assigning work {0} ", i); 

     StartThead(i, maxThreadSemaphore); 
    } 
} 

static void StartThead(int i, SemaphoreSlim maxThreadSemaphore) 
{ 
    Task.Factory.StartNew(
     () => DoWork(i.ToString()), 
     TaskCreationOptions.None 
    ).ContinueWith((task) => maxThreadSemaphore.Release()); 
} 

static void DoWork(string workname) 
{ 
    Thread.Sleep(100); 
    Console.WriteLine("--work {0} starts", workname); 
    Thread.Sleep(1000); 
    Console.WriteLine("--work {0} finishes", workname); 
} 
関連する問題