【问题标题】:Console issue in .Net.Net 中的控制台问题
【发布时间】:2010-03-02 12:17:40
【问题描述】:

我只是在学习如何在 C# 中使用线程机制。 我从 msdn 中拿了一个例子,并对其进行了修改,以设计一个像这样的简单游戏。 但问题是 DoWork 方法中的 while 循环甚至在从主程序调用 DoWork 方法之前读取键。 IE。当您在“Go:”出现在屏幕上之前运行程序时,如果您在 DoWork 方法中的循环读取键时键入一些内容。但是在屏幕上打印“Go:”后,控制权应该传递给while循环,对。有人可以解释一下为什么会这样。谢谢你。

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

}

【问题讨论】:

  • 如果 .Net 4.0 是一个选项,我会等一个多月,整个线程世界很容易提高 100 倍。
  • 奇怪...我已经尝试过您的代码,它运行良好。好吧,这不是证据,但我不知道为什么它不起作用
  • 也许您应该更改您的问题标题,因为问题似乎不是线程问题,而是控制台问题。在这种情况下,您获得好的解决方案的机会会更高。

标签: c# multithreading console


【解决方案1】:

Joe Albahari 的 free ebook on threading 是一个很好的介绍。

【讨论】:

  • 里面有世界。通读全文可能需要一周时间。
【解决方案2】:

这并不是真正的线程问题。这更像是一个控制台问题。

如果您在控制台中按任意键,它将从 Console 类缓冲,ReadKey() 函数只获取该缓冲区中的第一个字符。

【讨论】:

  • 我认为这是唯一真正解决 OP 困惑的答案。
  • @Nani:我很少在我的程序中使用控制台,所以很遗憾我没有遇到这个问题,所以我从来不用寻找解决方案。
【解决方案3】:

您的主线程恰好分裂了 1 个线程,然后等待它结束。线程没有任何目的,只是它使事情复杂化。

线程第 1 课:

使用线程并不总是一种改进。

【讨论】:

  • 你是对的,但我想这是出于培训目的
  • @PierrOz:我知道,但选择正确的问题区域进行学习/培训非常重要。
【解决方案4】:

【讨论】:

    【解决方案5】:

    使用Console.Out.Flush() 刷新控制台是否有帮助?当您的第二个线程已经在运行时,您的主线程的输出可能正在输出缓冲区中等待。

    【讨论】:

      【解决方案6】:

      我将使用另一个可能更合适的线程示例,通过 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 控件,以便通过 BackgroundWorker.ProgressChanged() 方法将加载过程的进度报告给 SplashForm。您可能还希望在 BackgroundWorker 完成后 Dispose() 您的 SplashForm。这可以通过 BackgroundWorker.RunWorkerCompleted() 方法完成。

      按照我们的示例,您必须将 SplashForm 声明放在 appForm_Load() 方法之外,以便 BackgroundWorker.RunWorkerCompleted() 方法可以访问它以进行处理,然后您的主表单将显示。

      根据我的谦虚,这是进行多线程的最有效和最简单的方法。 BackgroundWorker 对程序员非常友好,无需过多关注锁定内容、委托、调用和回调。

      .NET Framework 4 应附带许多工具,使多线程更容易完成:线程安全集合、并行 LINQ 等。

      【讨论】:

        【解决方案7】:

        我得到了解决方案。 实际问题在于 ReadKey(); 它不从键盘读取。 也许,它需要缓冲区数据。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-06-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多