请查看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。
答案 0 :(得分:4)
你对错误的例子完全正确。它刚刚破裂。
它不起作用的原因是它不会等待&
完成,而是等待Task
。这将解决它:
替换:
Console.ReadLine
使用:
Task.Run(() => NonBlockingConsumer(numberCollection, cts.Token));
Task.Run(() => NonBlockingProducer(numberCollection, cts.Token));