Console.ReadKey () not working

Check out the original Microsoft example .

In the second example, we find the following code:

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

(Full code needed to run this :)

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

What this code should do is perfectly clear: it should be interrupted by pressing c , but it does not work. Instead, it works to the end, asking you to close Enter .

How can we fix this?

This seems to be a thread issue, but this is a demo for .net4.5 and the code is not working.

KeyPress from 'c' does not set a CancelationToken.

+5
source share
1 answer

You are absolutely right that the example is wrong. It is simply broken.

The reason it doesn't work is because it doesn't wait when Task s finishes, instead it waits for Console.ReadLine . This will fix this:

Replace:

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

WITH

 Task t1 = Task.Run(() => NonBlockingConsumer(numberCollection, cts.Token)); Task t2 = Task.Run(() => NonBlockingProducer(numberCollection, cts.Token)); Task.WaitAll(t1, t2); 
+4
source

All Articles