2014-12-02 244 views
2

当我在控制台窗口中使用滚动条时,所有线程和任务正在暂停。有什么方法可以防止这种情况发生?如何停止控制台暂停我的线程和任务?

例如:

Task.Run(async() => 
      { 
       for (var z = 0; true; z++) 
       { 
        Console.WriteLine(z); 
        await Task.Delay(200); 
       } 
      }); 

var s = new Thread(() => 
      { 
       for (var z = 0; true; z++) 
       { 
        Console.WriteLine(z); 
        Thread.Sleep(200); 
       } 
      }); 

如果你运行这些代码示例作为控制台应用程序中的任何一个,都将这样做:打印一些数字。执行过程中,用鼠标左键按住滚动条一段时间,数字就会停止。任务/线程已暂停。当你释放鼠标按钮时,数字将继续。

由于滚动条释放后的数字跟在前一个数字之后,控制台并没有简单地停止数字的输出。它一直在Console.WriteLine - 方法中等待,直到释放滚动条。

有谁知道如何解决我的问题?

+2

你的程序只是暂停,因为你已经阻止了输出。即如果该节目不打电话,例如'Console.WriteLine()',它会继续运行得很好。事实上,任何线程_not_都不会试图写入输出(stdout或stderr)将继续运行。所以,要么不要阻塞输出,要么不写输出就运行重要的东西。 – 2014-12-02 21:39:14

回答

3

你可以做些什么来阻止这一点。当你按住滚动条时,Console.WriteLine将会阻塞,这与线程或任务完全无关。下面的小程序显示了同样的问题。

using System; 
using System.Threading; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      for (var z = 0; true; z++) 
      { 
       Console.WriteLine(z); 
       Thread.Sleep(200); 
      } 
     } 
    } 
} 

你不能改变的Console.WriteLine行为你能做的唯一的事情就是把你和写入控制台之间的缓冲。

using System; 
using System.Collections.Concurrent; 
using System.Threading; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      //The writer lives in another thread. 
      var s = new Thread(ConsoleWriter); 
      s.Start(); 

      for (var z = 0; true; z++) 
      { 
       //This add call does not get blocked when Console.WriteLine gets blocked. 
       LinesToWrite.Add(z.ToString()); 
       Thread.Sleep(200); 
      } 
     } 

     static void ConsoleWriter() 
     { 
      foreach (var line in LinesToWrite.GetConsumingEnumerable()) 
      { 
       //This will get blocked while you hold down the scroll bar but 
       // when you let go it will quickly catch up. 
       Console.WriteLine(line); 
      } 
     } 

     static readonly BlockingCollection<string> LinesToWrite = new BlockingCollection<string>(); 
    } 
} 

这仅仅是一个快速和肮脏的解决方案,这一点,有解决这个的其他方法,使之更加透明像制作从TextWriter衍生,将缓冲呼叫类和使用到一个呼叫类Console.SetOut(

0

如果您不希望代码在访问控制台时被锁定(在这种情况下由用户),并且不等待异步操作完成,则需要异步写入控制台然后继续。这可以简单地使用Task.Run(() => Console.WriteLine(z))代替Console.WriteLine(z)来完成。

您还需要复制(在致电Run之前)任何已结束变量的副本,这些变量在调用Task.Run之后最终会发生变化,因为闭合会关闭变量而不是值。

这就是说,这是一个强烈的迹象表明,你应该在这里重新考虑你的设计。也许控制台不适合您输出数据;另一种类型的UI可能是合适的。