Console.ReadKey()无效

时间:2015-07-17 07:11:35

标签: c# .net

请查看original Microsoft example

在第二个例子中,我们找到以下代码:

// The simplest UI thread ever invented.
Task.Run(() =>
{
    if (Console.ReadKey().KeyChar == 'c')
        cts.Cancel();
});

(运行此代码需要完整代码:)

static int inputs = 2000;
static void Main(string[] args)
{
    // The token source for issuing the cancelation request.
    CancellationTokenSource cts = new CancellationTokenSource();

    // A blocking collection that can hold no more than 100 items at a time.
    BlockingCollection<int> numberCollection = new BlockingCollection<int>(100);

    // Set console buffer to hold our prodigious output.
    //Console.SetBufferSize(80, 2000);

    // The simplest UI thread ever invented.
    Task.Run(() =>
    {
        if (Console.ReadKey().KeyChar == 'c')
            cts.Cancel();
        else
        {
            Debugger.Break();
        }
    });

    // Start one producer and one consumer.
    Task.Run(() => NonBlockingConsumer(numberCollection, cts.Token));
    Task.Run(() => NonBlockingProducer(numberCollection, cts.Token));

    Console.WriteLine("Press the Enter key to exit.");
    Console.ReadLine();
}

static void NonBlockingConsumer(BlockingCollection<int> bc, CancellationToken ct)
{
    // IsCompleted == (IsAddingCompleted && Count == 0)
    while (!bc.IsCompleted)
    {
        int nextItem = 0;
        try
        {
            if (!bc.TryTake(out nextItem, 0, ct))
            {
                Console.WriteLine(" Take Blocked");
            }
            else
                Console.WriteLine(" Take:{0}", nextItem);
        }

        catch (OperationCanceledException)
        {
            Console.WriteLine("Taking canceled.");
            break;
        }

        // Slow down consumer just a little to cause
        // collection to fill up faster, and lead to "AddBlocked"
        Thread.SpinWait(500000);
    }

    Console.WriteLine("\r\nNo more items to take. Press the Enter key to exit.");
}

static void NonBlockingProducer(BlockingCollection<int> bc, CancellationToken ct)
{
    int itemToAdd = 0;
    bool success = false;

    do
    {
        // Cancellation causes OCE. We know how to handle it.
        try
        {
            // A shorter timeout causes more failures.
            success = bc.TryAdd(itemToAdd, 2, ct);
        }
        catch (OperationCanceledException)
        {
            Console.WriteLine("Add loop canceled.");
            // Let other threads know we're done in case
            // they aren't monitoring the cancellation token.
            bc.CompleteAdding();
            break;
        }

        if (success)
        {
            Console.WriteLine(" Add:{0}", itemToAdd);
            itemToAdd++;
        }
        else
        {
            Console.Write(" AddBlocked:{0} Count = {1}", itemToAdd.ToString(), bc.Count);
            // Don't increment nextItem. Try again on next iteration.

            //Do something else useful instead.
            UpdateProgress(itemToAdd);
        }

    } while (itemToAdd < inputs);

    // No lock required here because only one producer.
    bc.CompleteAdding();
}

static void UpdateProgress(int i)
{
    double percent = ((double)i / inputs) * 100;
    Console.WriteLine("Percent complete: {0}", percent);
}

该代码应该做的完全清楚:它应该在按下c时中断,但它不起作用。相反,它会一直运行到最后要求关闭Enter

我们如何解决这个问题?

这似乎是一个线程问题,但它是.net4.5的演示,但代码无效。

&#39;&#39;的键盘。没有设置CancelationToken。

1 个答案:

答案 0 :(得分:4)

你对错误的例子完全正确。它刚刚破裂。

它不起作用的原因是它不会等待&完成,而是等待Task。这将解决它:

替换:

Console.ReadLine

使用:

Task.Run(() => NonBlockingConsumer(numberCollection, cts.Token));
Task.Run(() => NonBlockingProducer(numberCollection, cts.Token));