Проблема с консолью в .Net - PullRequest
3 голосов
/ 02 марта 2010

Я только учусь работать с механизмом потоков в C #. Я взял пример из msdn и изменил его, чтобы создать простую игру, подобную этой. Но проблема в том, что цикл while в методе DoWork читает ключи еще до вызова метода DoWork из основной программы. Я, д. Когда вы запускаете программу до того, как на экране появляется «Go:», если вы набираете что-то, когда цикл в методе DoWork читает ключи. Но управление должно быть передано циклу while после печати «Go:» на экране справа. Может кто-нибудь любезно объяснить мне, почему это происходит так. Благодарю вас.

 public class Worker    
{
  ConsoleKeyInfo cki;  
  StringBuilder sb = new StringBuilder();
  bool f = true;

// This method will be called when the thread is started.
public void DoWork()
{
    Console.SetCursorPosition(49, 8);
    Console.Write("Go:");
    Console.SetCursorPosition(53, 8);

    while (!_shouldStop)
    {         
       cki = Console.ReadKey(true);
       if (f == true && (65 <= Convert.ToInt32(cki.Key) && Convert.ToInt32(cki.Key) <= 90))
       {
           Console.Write(cki.Key.ToString());               
           sb.Append(cki.Key.ToString());
       }  
    }
    while (true)
    {
        if (cki.Key.ToString() == "Enter") break;
        cki = Console.ReadKey(true);
        if (cki.Key.ToString() == "Enter") break;
    }
}
public void RequestStop(string word)
{
    _shouldStop = true;
    f =false;
    Console.WriteLine();
    Console.SetCursorPosition(44, 10);
    Console.WriteLine("- TIME OUT -");
    Console.SetCursorPosition(46, 12);
    if (sb.ToString() == word.ToUpper())
    {
        Console.WriteLine("CORRECT !");
        Console.SetCursorPosition(42, 13);
        Console.WriteLine("CONGRATULATIONS");
    }
    else { Console.SetCursorPosition(47, 12); Console.WriteLine("WRONG !"); }
    Console.SetCursorPosition(40, 15);
    Console.WriteLine("Press [Enter] to quit");
    Console.CursorVisible = false;
}

 private volatile bool _shouldStop;

}

public class WordPlay
{
  static void Main()
  {
    Console.SetBufferSize(100,50);
    Console.SetWindowSize(100,50);
    string[] words = { "angstrom", "abacinate", "abactinal", "abandoned", "Babesiidae", "babirussa", "Babylonian", "bacchantic", "cabassous", "cableway" };
    string word="";      
    Random randObj = new Random(0);
    Console.SetCursorPosition(40, 6);
    Console.WriteLine("Your String:");
    Console.WriteLine();       
    for (int j = 0; j < 20; j++)
    { 
       System.Threading.Thread.Sleep(150); Console.SetCursorPosition(53, 6); 
       Console.Write(words[randObj.Next(words.Length - 1)].ToUpper() + "     ");  
    }

    word = words[randObj.Next(words.Length - 1)].ToUpper();
    Console.SetCursorPosition(53, 6);
    Console.Write( word+"    ");
    Console.WriteLine();

    // Create the thread object. This does not start the thread.
    Worker workerObject = new Worker();
    Thread workerThread = new Thread(workerObject.DoWork);

    // Start the worker thread.
    workerThread.Start();

    // Loop until worker thread activates.
    while (!workerThread.IsAlive);

    // Put the main thread to sleep for 1 millisecond to
    // allow the worker thread to do some work:

    Thread.Sleep(3000);
    // Request that the worker thread stop itself:

    workerObject.RequestStop(word);

    // Use the Join method to block the current thread 
    // until the object's thread terminates.

    workerThread.Join();      
}

}

Ответы [ 7 ]

3 голосов
/ 02 марта 2010

Это на самом деле не проблема с многопоточностью. Это больше проблема консоли.

Если вы нажмете любую клавишу в консоли, она будет буферизована из класса Console, а функция ReadKey() просто получит первый символ в этом буфере.

3 голосов
/ 02 марта 2010

Бесплатная электронная книга Джо Албахари по созданию потоков - отличное введение.

2 голосов
/ 02 марта 2010

Ваш основной поток разделяется на 1 поток, а затем ожидает его завершения Поток не имеет смысла, кроме того, что он усложняет вещи.

Threading Lesson # 1:

Использование потоков не всегда является улучшением.

1 голос
/ 02 марта 2010

Я буду использовать другой, вероятно, более подходящий пример для многопоточности через компонент BackgroundWorker, который является простым в использовании многопоточным инструментом. Допустим, у меня есть проект с двумя окнами, одно из которых является моим приложением, другое предназначено для использования в качестве SplashScreen во время загрузки приложения. Компонент BackgroundWorker отлично подходит для таких задач.

using System.ComponentModel.Component;

private BackgroundWorker newThread = new BackgroundWorker();

public void appForm_Load(object sender, EventArgs e) {
    SplashForm sf = new SplashForm();
    sf.Parent = this;

    newThread.DoWork += new EventHandler(newThread_DoWork);
    newThread.RunWorkerAsync(); // Here starts the thread.

    sf.ShowDialog(); // Then shows your splash screen.
}

public void newThread_DoWork(object sender, DoWorkEventArgs e) {
    // TODO: Place the code required by yours tasks here, or call another method to do so.
}

Это простой пример. Предполагая, что это скомпилируется, он будет выполнять ваши фоновые задачи в другом потоке, продолжая показывать вам заставку. На этом заставке вы можете разместить элемент управления ProgressBar, чтобы процесс загрузки загружался в SplashForm через метод BackgroundWorker.ProgressChanged (). Вы также можете захотеть Dispose () вашего SplashForm, когда BackgroundWorker будет сделано. Это можно сделать с помощью метода BackgroundWorker.RunWorkerCompleted ().

Следуя нашему примеру, вы должны будете взять объявление SplashForm за пределами вашего метода appForm_Load (), чтобы метод BackgroundWorker.RunWorkerCompleted () мог получить к нему доступ для целей удаления, после чего должна отображаться ваша основная форма.

Это, на мой взгляд, самый эффективный и простой способ сделать многопоточность. BackgroundWorker очень удобен для программистов, ему не нужно много заботиться о блокировке, делегатах, вызовах и обратных вызовах.

.NET Framework 4 поставляется с множеством инструментов, позволяющих упростить многопоточность: коллекции Threadsafe, параллельный LINQ и т. Д.

1 голос
/ 02 марта 2010

Помогает ли сбросить консоль с Console.Out.Flush()?Возможно, ваш вывод из основного потока ожидает в буфере вывода, пока второй поток уже запущен.

1 голос
/ 02 марта 2010
0 голосов
/ 03 марта 2010

Я получил решение.Фактическая проблема с ReadKey ();Он не читает с клавиатуры.Возможно, это займет буфер данных.

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