2011-01-01 11 views
2

との奇妙な問題は、これが私のコードです:シンプル素数プログラム - スレッドC#

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 

namespace FirePrime 
{ 
    class Program 
    { 
     static bool[] ThreadsFinished; 
     static bool[] nums; 

     static bool AllThreadsFinished() 
     { 
      bool allThreadsFinished = false; 
      foreach (var threadFinished in ThreadsFinished) 
      { 
       allThreadsFinished &= threadFinished; 
      } 
      return allThreadsFinished; 
     } 

     static bool isPrime(int n) 
     { 
      if (n < 2) { return false; } 
      if (n == 2) { return true; } 
      if (n % 2 == 0) { return false; } 
      int d = 3; 
      while (d * d <= n) 
      { 
       if (n % d == 0) { return false; } 
       d += 2; 
      } 
      return true; 
     } 

     static void MarkPrimes(int startNumber,int stopNumber,int ThreadNr) 
     { 
      for (int j = startNumber; j < stopNumber; j++) 
       nums[j] = isPrime(j); 
      lock (typeof(Program)) 
      { 
       ThreadsFinished[ThreadNr] = true; 
      } 
     } 

     static void Main(string[] args) 
     { 
      int nrNums = 100; 
      int nrThreads = 10; 
      //var threadStartNums = new List<int>(); 

      ThreadsFinished = new bool[nrThreads]; 

      nums = new bool[nrNums]; 
      //var nums = new List<bool>(); 
      nums[0] = false; 
      nums[1] = false; 
      for(int i=2;i<nrNums;i++) 
       nums[i] = true; 

      int interval = (int)(nrNums/nrThreads); 
      //threadStartNums.Add(2); 
      //int aux = firstStartNum; 
      //int i = 2; 
      //while (aux < interval) 
      //{ 
      // aux = interval*i; 
      // i=i+1; 
      // threadStartNums.Add(aux); 
      //} 

      int startNum = 0; 

      for (int i = 0; i < nrThreads; i++) 
      { 

       var _thread = new System.Threading.Thread(() => MarkPrimes(startNum, Math.Min(startNum + interval, nrNums), i)); 
       startNum = startNum + interval; 
       //set the thread to run in the background 
       _thread.IsBackground = true; 
       //start our thread 
       _thread.Start(); 
      } 

      while (!AllThreadsFinished()) 
      { 
       Thread.Sleep(1); 
      } 

      for (int i = 0; i < nrNums; i++) 
       if(nums[i]) 
        Console.WriteLine(i); 
     } 
    } 
} 

これは、並列に動作するnrThreadsスレッドを使用して最初のnrNums素数を見つけて出力することになって、かなり簡単なプログラムでなければなりません。

だから、私はちょうどnrThreads等しいチャンクにnrNumsを分割(ウェル、最後のものは等しくならない。nrThreadsnrNums除算しない場合、それはまた、コースの残りの部分を含むであろう)。

私はnrThreadsスレッドを開始します。

これらのすべてはそれぞれのチャンク内の各番号をテストし、プライムであるかどうかを確認します。彼らはすべての素数のタブを保持するブール配列ですべてをマークします。

スレッドはすべて、完了すると別のブール値配列ThreadsFinishedの特定の要素をtrueにします。

今、奇妙な部分が始まります。

スレッド決してすべて終了。私がデバッグした場合、私はThreadNrが私がループでそれに割り当てるものではなく、別の値であることが分かります。 スレッドは後で実行され、カウンター(変数i)はすでにそれまでに増加しているので、これは正常ですが、コードを正しくする方法を理解できません。

誰でも手助けできますか?

ありがとうございます。

P .:私はアルゴリズムがあまり効率的ではないことを知っています。私はEratosthenesのふるいを使ってxスレッドを使うという解決策を目指しています。しかし、今のところ私はこれを動作させることさえできず、私が理解できる言語のどこにでもそのアルゴリズムの実装の例は何も見つかりませんでした。

+1

だけで簡単にドライブバイコメント:代わりに '()'偽でAllThreadsFinished、あなたは[参加]する必要がありながら、ループの(http://msdn.microsoft.com/en-us/library/95hbf2ta。 aspx)を各スレッドごとに1つずつ実行します。各呼び出しは、それぞれのスレッドが終了するまでブロックします。これは、スレッドが終了するのを待つCPU効率の良い方法です。 – cdhowie

+0

エラトステネスのふるいは並列化できません:素数が1つあり、それは素数ではないとみなされます。あなたは次のマークされていない番号に移動し、素数で繰り返しているので、それを印刷します。 2つの別々のスレッドは何をしますか? –

+0

@コスミン・プランズそれは、ここにhttp://cs-alb-pc3.massey.ac.nz/notes/59735/seminars/01077635.pdfと書くことができ、アルゴリズムを与えることができます。私は多くの問題を研究していませんでしたが、私はそれを非並列的にしか実装していませんでした。私は素数を見つける最速の方法の一つであることを知っていたので、私はそれを言いました。 – Para

答えて

5

スレッドが受け取る値は、スレッドの実行時に保持される値の1つです(startNum)。それはローカル変数に値をコピー解決するには、次の

for (int i = 0; i < nrThreads; i++) 
{ 
var localStartNum = startNum; // save value in local variable 
            // and use in the thread start 
    var localIndex = i; 

var _thread = new System.Threading.Thread(() => 
         MarkPrimes(localStartNum, 
           Math.Min(localStartNum + interval, nrNums), 
           localIndex)); 
startNum = startNum + interval; 
_thread.IsBackground = true; 
_thread.Start(); 
} 

コード内の別のバグがすべてのスレッドを待っています:

スレッドを同期させる際に少しを助けることができる
static bool AllThreadsFinished() 
{ 
    bool allThreadsFinished = true; // Initialize to true instead of false 
            // Otherwise, all ANDs will result false 
    foreach (var threadFinished in ThreadsFinished) 
    { 
     allThreadsFinished = threadFinished; 
    } 

    return allThreadsFinished; 
} 

一つのヒント:あなたがすることができますすべてのスレッドをリストに保存してメインスレッドから参加させる。

var threads = new List<Thread>(); 

for (int i = 0; i < nrThreads; i++) 
{ 
var localStartNum = startNum; // save value in local variable 
            // and use in the thread start 
var _thread = new System.Threading.Thread(() => 
         MarkPrimes(localStartNum, 
           Math.Min(localStartNum + interval, nrNums), i)); 
startNum = startNum + interval; 
_thread.IsBackground = true; 
_thread.Start(); 
    threads.Add(_thread); 
} 

foreach(var thread in threads) 
{ 
    thread.Join(); 
} 
+0

いいえ、まだすべてのスレッドは決して終わらない。何も変わっていません。 – Para

+0

@Para、そうです、もう一つのバグがコードにあります。 'AllThreadsFinished'は常にfalseを評価します。それに応じて答えを更新。 – Elisha

+0

ああ、そうですね、ありがとう。今は馬鹿だと感じる。しかし、欠けていた地元の宣言は大失敗だった。ありがとう – Para