2011-01-21 49 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); 
     } 
    } 

眼下它似乎并不认为,“提示”线程被终止,因此它的第二个问题开始时崩溃。

所以我需要一个解决方案!我当然不介意回答问题来帮助自己得到答案。

+0

你可能想看看这个问题,我认为是相关的解决方案:http://stackoverflow.com/questions/142826/is-there-a-way-to-indefinitely-pause-a-thread/143153#143153 – blueberryfields 2011-01-21 01:08:34

回答

0

你有什么证据证明提示线程没有终止?主线程应该等待提示线程在“连接”位置终止,因此,如果执行继续经过连接,则“提示”线程将终止。

+0

它不会等待它终止,而是等待30秒才能通过。 – 2011-01-21 01:15:43

+0

对。他没有使用任何东西的返回值。 – blueberryfields 2011-01-21 01:17:46

+0

如何检索该返回值并检查它? – 2011-01-21 01:24:45

2

方法Thread.Join(Int32)不会在给定的毫秒数后停止另一个线程。它只是停止等待。如果其他线程已终止,则返回true。

因此,如果ask.Join(30000);返回false,另一个线程仍在运行,您必须自行中止线程。

0

Console.ReadLine阻止当前线程被中止,直到该行被读取。 (按从Timwi评论)

要解决这个问题,你就必须在这里使用的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

看看在MSDN的Thread.Join()页面上的示例。该示例使用两种不同的方法将工作传递给线程。 regularThread是你正在尝试做的。对于你的例子中的简单任务,我认为在没有事件或锁的情况下做一个join()是一个合理的解决方案。如果你正在做一个比你的例子更强大的产品原型,那么你还应该:1)阅读ThreadPool。它避免了创建/处理线程的成本。 2)将lock()块放在对answer变量的读写中。

一句警告:其他答案提到使用Thread.Abort()。在当前正在执行的线程上调用Thread.Abort()很好,几乎相当于抛出异常。但是应该避免在不同的线程上调用Thread.Abort()。有几种情况会导致线程无法正常清理。