C#如何使用eventhandler处理取消任务

时间:2018-05-17 09:49:35

标签: c# .net task eventhandler cancellation

我需要在依赖服务的状态发生变化时更新ui控制。我有这个示例代码,轮询服务api获取状态并发送结果重新计算并通过主线程更新ui:

public void StartObserving() {
this.cts = new CancellationTokenSource();
this.cts.Token.ThrowIfCancellationRequested();
this.isRunning = true;
var token = this.cts.Token;

Task.Run(async () =>
{
    try
    {
        while (this.isRunning)
        {
            var result = this.serviceAPI.GetStatus();
            this.OnServiceStatusChanged(result);

            await Task.Delay(3000);
        }
    }
    catch (OperationCanceledException)
    {
        this.isRunning = false;
    }
    catch (Exception ex)
    {
        this.isRunning = false;
        this.logger.LogError(ex);
    }
}, token);
}

问题是我想取消上面的任务。当我在这个类的另一个方法中调用this.cts.Cancel()时,我得到了Exception'一个任务被取消了#39;在由EventHandler触发的调度程序上:OnServiceStatusChanged

我应该如何正确实施这种情况?

3 个答案:

答案 0 :(得分:0)

我只是检查内部循环中是否取消了令牌,如果是,则退出循环。无需将令牌传递给Task.Run()方法。

public void StartObserving()
{
    this.cts = new CancellationTokenSource();
    var token = this.cts.Token;

    Task.Run(async () =>
    {
        try
        {
            while (!token.IsCancellationRequested)
            {
                var result = this.serviceAPI.GetStatus();
                this.OnServiceStatusChanged(result);
                await Task.Delay(3000);
            }
        }
        catch
        {
        }
    });
}

答案 1 :(得分:0)

尝试在控制台应用中模拟此行为。任务开始了,但是在调用cts.Cancel()之后,任务继续执行......非常奇怪。

但是,我可以通过简单地将this.isRunning设置为false来取消该任务(而不是调用cts.Cancel())。但我不确定这是否是你想要的解决方案。

答案 2 :(得分:0)

如果dfs = {k:pd.DataFrame(v) for k, v in d.items()} print (dfs['categories']) category_id ... vela_defined 0 11decadd ... True 1 c7010763 ... True [2 rows x 7 columns] print (dfs['customizable_categories']) category_id ... updated_at 0 11decadd ... 2017-02-15 01:49:23 -0700 1 fafab667 ... 2017-02-15 01:49:23 -0700 [2 rows x 6 columns] print (dfs['equipment_category_status_sets']) Empty DataFrame Columns: [] Index: [] 是一个等待无效的阻止调用,那么您无法正确取消此任务。

正确取消serviceAPI.GetStatus()方法涉及使用async标记安全取消点。

您必须将CancellationToken.ThrowIfCancellationRequested()重写为serviceAPI.GetStatus()方法async的结果。它应该包含对可以安全取消的点await的调用。您可能希望将取消令牌传递给两者该方法,并调用CancellationToken.ThrowIfCancellationRequested()以获得最佳性能。