多次使用线程

时间:2011-01-21 00:55:22

标签: c# multithreading variables

我试图多次使用一个线程,如果用户反应不够快,让线程停止处理。

 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);
        }
  }

现在似乎“提示”线程似乎没有终止,所以当第二个问题开始时它会崩溃。

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

4 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:0)

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

答案 2 :(得分: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. 
    }
}

答案 3 :(得分:0)

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

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