我有个密码。这样做的目的是取消一个带有CancellationToken,的任务,我知道它可以用返回; in循环,但是我想用CancellationToken.来完成它。我试着去做,但它不起作用,我也不知道为什么。
任务中断dropNumber上的任务循环
static CancellationTokenSource cancellationTokenSource = null;
static async Task Main(string[] args)
{
cancellationTokenSource = new CancellationTokenSource();
try
{
Task.Run(() => CountLoopAsync(cancellationTokenSource.Token, 4),cancellationTokenSource.Token);
}
catch(OperationCanceledException ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.BackgroundColor = ConsoleColor.White;
Console.WriteLine("Task is cancelled!");
Console.ResetColor();
}
finally
{
cancellationTokenSource.Dispose();
}
}
private static void CountLoopAsync(CancellationToken token, int dropNumber)
{
for(int i = 0; i < 10; i++)
{
Console.WriteLine(i);
if (dropNumber == i)
{
cancellationTokenSource.Cancel();
}
}
}
}发布于 2022-03-18 15:14:31
你的Task.Run,它已经完成了等待,所以你不会去取消句子,直到任务完成。使用Task.Run而不等待允许继续运行并执行取消
更新
我认为您的示例如果不是很好,因为您试图以顺序方式执行所有代码,而任务的使用通常是在后台以异步形式运行代码。此外,我认为使用预定义值停止是一种非意义的做法:在这种情况下,更改"for“中的最后一步,而不是使用令牌。你不能在任务代码中取消。如果在该代码中知道何时取消,则只需返回。令牌的用途是允许外部取消任务代码。如果这样做,您就无法控制任务何时完成,因为它取决于外部的一些东西。例如,当用户单击“取消”按钮时,可能会出现这种情况。通常,您的计数器代码试图计算所有。但是,经过很长一段时间的操作,您随时都会给用户以取消的机会。
将代码封装在一个类中:
public class YourClass : IDisposable
{
private CancellationTokenSource _cancellationTokenSource = null;
private Task _task = null;
public void Wait(int milliSeconds)
{
this._task.Wait(milliSeconds, this._cancellationTokenSource.Token);
}
public void Dispose()
{
this._cancellationTokenSource?.Dispose();
this._task?.Dispose();
}
public async Task RunLongOperationInBackground()
{
this._cancellationTokenSource = new CancellationTokenSource();
this._task = Task.Run(
() => CountLoopAsync(this._cancellationTokenSource.Token),
this._cancellationTokenSource.Token);
await this._task;
}
public void Abort()
{
// Cancel the operation
this._cancellationTokenSource?.Cancel();
}
private static void CountLoopAsync(CancellationToken token)
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i);
// Uncomment to simulate task takes some time to finish
//Thread.Sleep(3000);
// You don't know when the action will be cancelled. If you know that, you don't
// need the cancellation: you can do the for until your well known end
if (token.IsCancellationRequested)
{
break;
}
}
}
}这个类允许您运行一个操作(RunLongOperationInBackground),也可以在任何时候取消操作(中止)。因此,您运行您的任务,并在任何时候,您可以取消任务。如果查看CountLoopAsync代码,它尝试执行所有内容,但它有时会检查令牌(在本例中的每次迭代中),如果有人请求取消,则退出for。但你可以随心所欲。例如,您可能一直运行到下一个100,因此,即使令牌已被取消,您也可以继续运行到下一个100。或者,如果在操作接近结束时要求取消,您可以决定继续。代币只告诉你外面要终止。
使用2个按钮创建一个表单(而不是一个控制台),这是一个更现实的例子:
public partial class Form1 : Form
{
private readonly YourClass _yourClass;
public Form1()
{
this.InitializeComponent();
this._yourClass = new YourClass();
}
private async void OnStartButtonClick(object sender, EventArgs e)
{
await this._yourClass.RunLongOperationInBackground();
}
private void OnCancelButtonClick(object sender, EventArgs e)
{
this._yourClass.Abort();
}
private void OnForm_FormClosed(object sender, FormClosedEventArgs e)
{
if (this._yourClass != null)
{
// Wait, for example 30 seconds before end the appication
this._yourClass.Wait(30000);
this._yourClass.Dispose();
}
}
}在构造函数中创建类。“开始”按钮运行您的长时间操作(您可能希望在每次迭代中使用延迟,以便能够在终止之前取消)。在任何时候,您都可以单击“取消操作”按钮来取消该操作。在那个时刻,在您的" for“中,令牌告诉您已被取消,然后退出for。
发布于 2022-03-18 18:46:44
我认为问题在于:
cancellationTokenSource.Dispose();cancellationTokenSource似乎被过早地处理了。您不应该在所有相关工作完成之前将其释放。在您的情况下,您可能必须等待Task.Run的完成才能调用Dispose。
Task.Run(() => CountLoopAsync(cancellationTokenSource.Token, 4),
cancellationTokenSource.Token).Wait();https://stackoverflow.com/questions/71529142
复制相似问题