Использование потока несколько раз - PullRequest
0 голосов
/ 21 января 2011

Я пытаюсь использовать поток несколько раз, и обработка потока прекращается, если пользователь не реагирует достаточно быстро.

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

Сейчас кажется, что поток "prompt" не завершается, и поэтому он падает, когда начинается второй вопрос.

Так что мне нужно решение! Конечно, я не против отвечать на вопросы, чтобы помочь себе получить ответ.

Ответы [ 4 ]

2 голосов
/ 21 января 2011

Метод Thread.Join(Int32) не останавливает другой поток после заданного количества миллисекунд. Это просто перестает ждать. Он возвращает истину, если другой поток завершен.

Так что, если ask.Join(30000); возвращает false, другой поток все еще работает, и вы должны прервать поток самостоятельно.

0 голосов
/ 21 января 2011

Посмотрите на пример на странице MSDN Thread.Join () . В примере используются два разных метода для передачи работы потоку. regularThread это то, что вы пытаетесь сделать. Для простой задачи в вашем примере, я думаю, что выполнение join () без событий или блокировок является разумным решением. Если вы создаете прототип, чтобы сделать продукт, который намного надежнее, чем предполагает ваш пример, то вам также следует: 1) прочитать файл ThreadPool . Это позволяет избежать затрат на создание / удаление потоков. 2) Поместите блок lock () вокруг операций чтения и записи в переменную answer.

Предупреждение: в других ответах упоминается использование Thread.Abort (). Вызов Thread.Abort () в текущем выполняющемся потоке - это нормально и почти эквивалентно выбрасыванию исключения. Однако следует избегать вызова Thread.Abort () в другом потоке. Есть несколько сценариев, в которых это может привести к неправильной очистке потока.

0 голосов
/ 21 января 2011

Console.ReadLine блокирует прерывание текущего потока до тех пор, пока строка не будет прочитана.(Согласно комментарию от Timwi)

Чтобы обойти это, вам придется использовать метод Console.KeyAvailable здесь: Как добавить Timeout в 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 голосов
/ 21 января 2011

Какие у вас есть доказательства того, что поток подсказок не заканчивается? Основной поток должен ожидать завершения потока приглашения в местах «соединения», поэтому, если выполнение продолжается после соединения, поток «приглашения» завершается.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...