取消另一个类 C# 中的任务
Posted
技术标签:
【中文标题】取消另一个类 C# 中的任务【英文标题】:Cancel task in another class C# 【发布时间】:2021-03-08 05:19:44 【问题描述】:我对 C# 中的 cancelTokenSource 有问题
public class Building
public CancellationTokenSource BuildTokenSource;
public void StartBuilt()
BuildTokenSource = new CancellationTokenSource();
buildingService.buildTask = Task.Run(async () =>
await clock.Delay(BUILT_TIME);
, BuildTokenSource.Token);
public void CancelBuilt()
if (BuildTokenSource != null)
BuildTokenSource.Cancel();
在另一个类中想要检测任务是否像这样取消但它不起作用。从未触发过的 catch 异常
public async Task<Building> GetBuildingOfUserTask()
double remainingTime = unitService.GetRemainingTime();
if (remainingTime <= 2000 && remainingTime > 0.0)
Building building = GetBuilding();
CancellationToken cancellation = building.BuildTokenSource.Token;
try
await buildTask;
catch (OperationCanceledException) when (cancellation.IsCancellationRequested)
return GetBuildingOfUser();
return GetBuildingOfUser();
有人知道为什么这不起作用,在这种情况下有解决方案吗?
【问题讨论】:
“它不起作用” 什么不起作用?编译器错误?例外?行为与预期不同? 任务没有取消。永远不会触发 catch 异常 相关:Using CancellationToken for timeout in Task.Run does not work 【参考方案1】:clock.Delay(BUILT_TIME)
是否有接受CancellationToken
的重载?如果是这样,请使用它。
问题是如果代码在您取消时已经在等待clock.Delay(BUILT_TIME)
,clock.Delay
将不知道它需要抛出异常。
【讨论】:
【参考方案2】:我没有看到任何地方调用CancelBuilt()
+ 你必须调用BuildTokenSource.Token.ThrowIfCancellationRequested()
才能引发OperationCanceledException
异常
token.Cancel()
应该在使用 cancelationToken 的异步方法之外调用。同样消费异步方法必须调用(通常在每一步)Token.ThrowIfCancellationRequested();
【讨论】:
【参考方案3】:我相信使用调解器 (Mediator design pattern) 会更合适。这实际上是一个 pub-sub 模型,它将在取消时发布一个事件并通知所有订阅者。
第一个类将中介实例作为引用(只读字段、属性)来发布取消事件,另一个类应该有相同的实例作为引用,以便在事件实际发生时得到通知。您应该注意的另一点是,当包含“GetBuildingOfUserTask”方法的类的实例被销毁时应该取消订阅。
你怎么看?
【讨论】:
【参考方案4】:我同意HadascokJ的回答,我想带来更多的光明。
您有一个主要任务从 Task buildingService.buildTask
开始,它的从属任务从 await clock.Delay(BUILT_TIME);
开始
第一个任务管理CancellationToken
,但从属的不是。为了更好地使用Task Task.Delay(int millisecondsDelay, CancellationToken cancellationToken);
替换您的clock.Delay(BUILT_TIME)
,当然还要提供CancelationToken
。您会看到,在这种情况下,从属任务将被取消。同时调用void CancellationToken.CancelAfter(int millisecondsDelay)
由于您没有为从属任务提供CancellationToken
,因此主任务已启动,主任务及其从属任务都不会被取消。
另一方面,要在从属任务执行时取消,向从属任务提供一些逻辑来管理CancelationToken
到其相应的方法中,并在必要时调用CancelationToken.ThrowIfCancellationRequested()
,这会抛出OperationCanceledException
.
至少,尝试将长任务分成几个小任务。
我用来管理异步。任务,必须按顺序运行到能够观察这些TaskStatus
的任务队列中。为了解决这个问题,如果你需要,我在 github 上有一个实现。我叫它FifoTaskQueue
【讨论】:
以上是关于取消另一个类 C# 中的任务的主要内容,如果未能解决你的问题,请参考以下文章