2011-01-21 21 views
0

私はスレッドを何度も使用しようとしています。スレッドを複数回使用する

Thread ask = new Thread (new ThreadStart (MathQuiz.prompt)); 
ask.Start(); 
ask.Join(30000); 
if (answer == 4) 
{ 
    score = score+1; 
    answer = 0; 
} 
Console.WriteLine(); 
Console.WriteLine("Press any key to move on to the next question!"); 
Console.WriteLine(); 
Console.ReadKey(true); 
Console.WriteLine("What is 15/3?"); 
Console.WriteLine(); 
ask.Start(); 
ask.Join(30000); 
if (answer == 5) 
{ 
    score = score+1; 
    answer = 0; 
} 

...

static void prompt() 
    { 
    preanswer = (Console.ReadLine()); 
    if (!decimal.TryParse(preanswer, out answer)) 
     { 
      Console.WriteLine("That wasn't even a number or decimal!"); 
     } 
    else 
     { 
      answer = decimal.Parse(preanswer); 
     } 
    } 

今のところは、「プロンプト」スレッドが終了していることを思われない、そして2番目の質問が始まるとき、それがクラッシュ。

だから私は解決策が必要です!私はもちろん、答えを得るのを助けるために質問に答えても構いません。

+0

この質問を見て、適切と思われる解決策を探してみるとよいでしょう。http://stackoverflow.com/questions/142826/is-there-a-way-to-indefinitely-pause-a-thread/143153#143153 – blueberryfields

答えて

0

プロンプトスレッドが終了していないという証拠はありますか?メインスレッドは、プロンプトスレッドが「ジョイン」場所で終了するのを待つ必要があります。したがって、実行がジョインを過ぎても継続する場合、「プロンプト」スレッドは終了します。

+0

終了するのを待っているわけではありません.30秒待っています。 –

+0

右。彼は何かの戻り値を使用していません。 – blueberryfields

+0

その戻り値を取得してチェックするにはどうすればよいですか? –

2

メソッドThread.Join(Int32)は、指定されたミリ秒後に他のスレッドを停止しません。待っているだけです。他のスレッドが終了した場合はtrueを返します。

したがって、ask.Join(30000);がfalseを返す場合、もう一方のスレッドはまだ実行されており、スレッドを自分で中止する必要があります。

+0

スレッドを中止するにはどうすればよいですか? –

0

Console.ReadLineは、現在のスレッドが行が読み込まれるまで中止されるのをブロックします。これを回避するには

(Timwiからコメントを1として)、あなたはここでConsole.KeyAvailableメソッドを使用しなければならないでしょう:How to add a Timeout to Console.ReadLine()?

私は私のミスを実現する前に、問題を再書き、今ここに解決策があります。

これは私が望んでいたよりもかなり複雑です。 (KeyAvailableを使用すると、私はキーが入力されたアップキューに、私はアイテムを削除する必要がバックスペースをサポートする必要があるということです。私も何のキーが用意されていない間にスリープ状態に必要があります...)

private static AutoResetEvent answered = new AutoResetEvent(false); 
private static Func<string, bool> questionCorrect = null; 
private static bool? correct; 

static void Main(string[] args) 
{ 
    int score = 0; 
    AskQuestion(ref score, 
       "What is 15/3?", 
       TimeSpan.FromSeconds(5), 
       answer => 
        { 
         decimal value; 
         if (!decimal.TryParse(answer, out value)) 
         { 
          Console.WriteLine(
           "That was not a valid number"); 
          return false; 
         } 

         return (value == 15/3); 

        }); 


    AskQuestion(ref score, 
       "What is 20 * 2 ?", 
       TimeSpan.FromSeconds(5), 
       answer => 
        { 
         decimal value; 
         if (
          !decimal.TryParse(answer, 
               out value)) 
         { 
          Console.WriteLine(
           "That was not a valid number"); 
          return false; 
         } 

         return (value == 20*2); 

        }); 


    Console.WriteLine("Done. Score: {0}", score); 
    Console.ReadLine(); 
} 

private static void AskQuestion(ref int score, string question, TimeSpan duration, Func<string, bool> validator) 
{ 
    // Setup 
    questionCorrect = validator; 
    correct = null; 
    answered.Reset(); 

    // Ask 
    Console.WriteLine(question); 
    Thread thread = new Thread(GetQuestion); 
    thread.Start(); 

    // Wait 
    answered.WaitOne(duration); 
    thread.Abort(); 
    thread.Join(); 

    Console.WriteLine(); // Write empty line, otherwise this overwrites the answer. 

    // Validate); 
    if (correct.HasValue && correct.Value == true) 
    { 
     score++; 
     Console.WriteLine("Correct"); 
    } 
    else if (correct.HasValue) 
    { 
     Console.WriteLine("Incorrect"); 
    } 
    else 
    { 
     Console.WriteLine("Timeout"); 
    } 

} 

private static void GetQuestion() 
{ 
    try 
    { 
     List<char> captured = new List<char>(); 
     bool answerCaptured = false; 
     while (!answerCaptured) 
     { 
      while (Console.KeyAvailable) 
      { 

       var key = Console.ReadKey(); 
       if (key.KeyChar == '\r' || key.KeyChar == '\n') 
       { 
        answerCaptured = true; 
        break; 
       } 

       if (key.KeyChar == '\b' && captured.Count > 0) 
       { 
        captured.RemoveAt(captured.Count - 1); 
       } 
       else 
       { 
        captured.Add(key.KeyChar); 
       } 
      } 
      Thread.Sleep(50); 
     } 
     string answer = new string(captured.ToArray()); 

     correct = questionCorrect.Invoke(answer); 
     answered.Set(); 
    } 
    catch (ThreadAbortException) 
    { 
     // will be thrown when the thread times out. 
    } 
} 
+0

私はこれを試して、最初の文章の主張が間違っていることを発見しました。 'Console.ReadLine'は他のスレッドをブロックしません。 – Timwi

+0

@ティムウイ - この場合のようです。入力方法を切り替えることができるように私の答えを編集しました。私が間違ったことを指摘してください。 –

+0

@ウィル:もう少し試してみましたが、 'thread.Abort()'は 'Console.ReadLine()'の中でスレッドを中断しないようです。 – Timwi

0

は見てみましょうMSDNのThread.Join()ページの例をご覧ください。この例では、2つの異なるメソッドを使用して、スレッドに作業を渡します。 regularThreadはあなたがやろうとしていることです。あなたの例の単純なタスクでは、イベントやロックを持たないjoin()を行うのが合理的な解決策だと思います。あなたの例が示すよりもはるかに頑強な製品を作るために試作しているならば、あなたはまた次のことをするべきです:1)ThreadPoolを読んでください。スレッドを作成/廃棄するコストを回避します。 2)ブロックlock()を変数answerに読み書きします。

警告の単語:Thread.Abort()を使用して他の回答が記載されています。現在実行中のスレッドでThread.Abort()を呼び出すことは問題なく、例外をスローすることとほぼ同じです。しかし、別のスレッドでThread.Abort()を呼び出すことは避けてください。スレッドが適切にクリーンアップされない場合があるいくつかのシナリオがあります。

関連する問題