尝试学习任务,等待和取消 从我认为是MSDN的简单样本开始 Task.Wait Method (CancellationToken)
作为控制台应用程序,它按预期运行 相同的代码在WPF中没有按预期运行 在WPF中t2运行完成 - 在调试中打印任务完成的行 它命中0到100000000之间的OperationCanceledException但是t2继续运行 (注意必须将其更改为ctr< Int32.MaxValue或它永远不会完成)
在.NET 4.5上,还尝试了4.51
public void TestCancel1()
{
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
Task.Run(() =>
{
cts.Cancel();
if (token.IsCancellationRequested)
Debug.WriteLine("Cancellation requested in Task {0}.",
Task.CurrentId);
}, token);
Task t2 = Task.Run(() =>
{
Debug.WriteLine(Int32.MaxValue.ToString());
for (Int32 ctr = 0; ctr < Int32.MaxValue; ctr++) //
{
if (ctr % 100000000 == 0)
Debug.WriteLine(ctr.ToString());
}
Debug.WriteLine("Task {0} finished.",
Task.CurrentId);
});
try
{
t2.Wait(token);
}
catch (OperationCanceledException)
{
Debug.WriteLine("OperationCanceledException in Task {0}: The operation was cancelled.",
t2.Id);
}
}
控制台应用程序上存在问题 这是代码
static void Main(string[] args)
{
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
Task.Run(() =>
{
Thread.Sleep(1000); // change number and will get a differnt last ctr
cts.Cancel();
if (token.IsCancellationRequested)
Console.WriteLine("Cancellation requested in Task {0}.",
Task.CurrentId);
}, token);
Task t2 = Task.Run(() =>
{
Console.WriteLine(Int32.MaxValue.ToString());
for (int ctr = 0; ctr < Int32.MaxValue; ctr++)
{
Console.WriteLine(ctr.ToString());
if (ctr % 100000000 == 0) Console.WriteLine(ctr.ToString());
}
Console.WriteLine("Task {0} finished.",
Task.CurrentId);
});
try
{
t2.Wait(token);
}
catch (OperationCanceledException)
{
Console.WriteLine("OperationCanceledException in Task {0}: The operation was cancelled.",
t2.Id);
}
}
添加了ThrowIfCancellationRequested
我在该行收到错误。用户代码未处理OperationCancelException
Task t2 = Task.Run(() =>
{
Debug.WriteLine(Int32.MaxValue.ToString());
for (Int32 ctr = 0; ctr < Int32.MaxValue; ctr++) //
{
if (ctr % 100000000 == 0)
{
Debug.WriteLine(ctr.ToString() + " " + token.IsCancellationRequested.ToString());
}
if (token.IsCancellationRequested)
token.ThrowIfCancellationRequested();
}
Debug.WriteLine("Task {0} finished.",
Task.CurrentId);
}); //, token);
好的,我知道这已经很久了 来自微软的样本充其量也是误导性的 - 为什么你会有一个取消的样本并没有真正取消 为了验证为什么Rohit说我添加了以下内容 当然,我可以在按下之前看到更多的传球,任何关键都可以继续
catch (OperationCanceledException)
{
Console.WriteLine("OperationCanceledException in Task {0}: The operation was cancelled.",
t2.Id);
Thread.Sleep(10);
Console.WriteLine("exit exception");
}
答案 0 :(得分:2)
您的 控制台 测试代码可能存在错误并且您的期望错误。在控制台应用程序中,2t继续运行,但程序在t2完成之前退出。
取消令牌来源是“合作取消”,如果您希望t2提前结束,则需要在取消发生时检查t2内部。
Task t2 = Task.Run(() =>
{
Debug.WriteLine(Int32.MaxValue.ToString());
for (Int32 ctr = 0; ctr < Int32.MaxValue; ctr++) //
{
if (ctr % 100000000 == 0)
Debug.WriteLine(ctr.ToString());
token.ThrowIfCancellationRequested();
}
Debug.WriteLine("Task {0} finished.",
Task.CurrentId);
});
答案 1 :(得分:1)
这与WPF无关。控制台应用程序,WPF或WinForms的输出相同。
作为控制台应用程序,它按预期运行。同样的代码 没有在WPF中按预期运行。在WPF中t2运行完成 - 该行 完成的任务将在debug中打印。
我怀疑你在使用ctr <= Int32.MaxValue
进行测试的控制台应用程序中这就是为什么没有打印Finised的原因,因为它无限运行并且Finish永远不会在控制台上打印出来。
它在0到100000000之间击中OperationCanceledException但是t2 继续跑步。
异常不会阻止任务t2执行完毕。
OperationCanceledException
被抛出主线程,因为您要求主线程等待任务t2并传递取消令牌。因此,通过捕获此异常,您的主线程不再等待任务t2完成,但这并不意味着任务t2将被停止。它将完全执行。此外,主线程现在可以继续执行其进一步的执行。
这让我得出另一个结论,即Console.ReadKey()
方法可能会遗漏Main
。这就是为什么你的控制台应用程序在异常被抛出后关闭的原因(主线程不再在任务t2上等待)。因此,您永远不会在控制台上看到Finish
打印(假设您使用ctr < Int32.MaxValue
运行循环)。
如果您希望停止任务t2,可以调用token.ThrowIfCancellationRequested();
,如果令牌IsCancellationRequested
设置为真,将导致任务t2停止。
for (int ctr = 0; ctr < Int32.MaxValue; ctr++)
{
token.ThrowIfCancellationRequested();
if (ctr % 100000000 == 0)
Debug.WriteLine(ctr.ToString());
}