You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用CancellationTokenSource实现邮件延迟标记已读(中途切换取消)?

实现邮件延迟标记已读的正确方案

核心逻辑要求

  • 打开未读邮件后,延迟3秒将其标记为已读
  • 若在超时前点击其他邮件,当前邮件保持未读(即取消当前的延迟标记任务)

正确实现代码

private readonly object _ctsLock = new object();
private CancellationTokenSource? _currentCts;

private async Task OnEmailClicked(int id)
{
    // 取消并清理之前未完成的延迟任务
    lock (_ctsLock)
    {
        _currentCts?.Cancel();
        _currentCts?.Dispose();
        _currentCts = null;
    }

    // 加载目标邮件内容
    await LoadEmail(id);

    // 创建新的取消令牌源,绑定当前任务
    CancellationTokenSource currentTaskCts;
    lock (_ctsLock)
    {
        currentTaskCts = _currentCts = new CancellationTokenSource();
    }

    try
    {
        // 等待3秒,期间若收到取消信号则抛出TaskCanceledException
        await Task.Delay(3000, currentTaskCts.Token);
    }
    catch (TaskCanceledException)
    {
        // 任务被取消,直接返回,不执行标记已读操作
        return;
    }
    finally
    {
        // 仅清理当前任务对应的令牌源,避免误清理新任务的资源
        lock (_ctsLock)
        {
            if (_currentCts == currentTaskCts)
            {
                _currentCts.Dispose();
                _currentCts = null;
            }
        }
    }

    // 延迟完成且未被取消,执行标记已读操作
    await MarkEmailAsRead(id);
}

关键实现细节

  • 线程安全保护:使用lock对象保护对_currentCts的所有操作,避免多线程并发点击时出现竞态条件(比如多个线程同时修改或清理令牌源)
  • 令牌源生命周期管理:
    • 每次点击新邮件时,先取消并清理之前的令牌源,确保旧任务不会继续执行
    • 创建新令牌源时,在锁内完成赋值,保证后续取消操作能精准指向当前任务
    • finally块中仅清理当前任务对应的令牌源,防止新邮件点击创建的令牌源被误清理
  • 取消逻辑处理:捕获TaskCanceledException后直接返回,终止当前任务的后续流程,确保被中断的邮件不会被标记为已读

内容的提问来源于stack exchange,提问作者lonix

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 14:25:18