如何阻止控制台暂停我的线程和任务?

时间:2014-12-02 21:34:33

标签: c# multithreading console

当我在控制台窗口中使用滚动条时,所有线程和任务都会暂停。有没有办法防止这种情况发生?

示例:

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 个答案:

答案 0 :(得分: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(

答案 1 :(得分:0)

如果您不希望代码在访问控制台时被阻止(在这种情况下是用户),则需要异步写入控制台,而不是等待异步操作完成之前继续。这可以像使用Task.Run(() => Console.WriteLine(z))代替Console.WriteLine(z)一样简单地完成。

您还需要复制(在调用Run之前)任何已关闭的变量,这些变量在调用Task.Run后最终会被变异,因为闭包会关闭变量而不是变量而不是价值观。

那就是说,这是一个强有力的迹象,你应该在这里重新考虑你的设计。也许控制台不是输出数据的正确方法;另一种类型的UI可能是合适的。