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

如何在C#中暂停任务?带确认弹窗的任务取消实现咨询

解决方案:带确认的任务取消与暂停实现

你当前的实现存在几个核心问题:

  • 手动维护的_isTaskCancelled、_isTaskPaused等bool变量非线程安全,多线程访问易出现竞态条件
  • 暂停逻辑依赖变量判断,无法让后台任务立即进入等待状态,弹窗期间任务可能仍在执行
  • CancellationToken和自定义状态变量混用,逻辑耦合混乱

下面是规范的实现方式,用ManualResetEventSlim实现线程安全的暂停/恢复,结合CancellationTokenSource处理取消,同时满足确认弹窗的交互需求:

核心组件定义

在窗口类中定义必要的线程安全字段:

private CancellationTokenSource _cts;
private ManualResetEventSlim _pauseEvent;
private Task _fileGenerationTask;
// 用锁保护文件生成状态,避免多线程冲突
private bool _isFile1Generated;
private bool _isFile2Generated;
private bool _isFile3Generated;
private readonly object _statusLock = new object();

后台任务实现

改写任务逻辑,用_pauseEvent.Wait()实现暂停,结合CancellationToken处理取消:

private async Task StartFileGenerationAsync()
{
    try
    {
        // 初始状态不暂停
        _pauseEvent.Set();
        
        // 逐个执行文件生成,每个步骤前检查暂停和取消信号
        await GenerateFile1Async(_cts.Token);
        await GenerateFile2Async(_cts.Token);
        await GenerateFile3Async(_cts.Token);
        
        // 所有文件生成完成后的状态更新
        lock (_statusLock)
        {
            _isFile1Generated = _isFile2Generated = _isFile3Generated = true;
        }
        // 切换到UI线程更新状态
        Dispatcher.Invoke(() => UpdateStatus("所有文件生成完成"));
    }
    catch (OperationCanceledException)
    {
        // 任务取消后的状态重置
        lock (_statusLock)
        {
            _isFile1Generated = _isFile2Generated = _isFile3Generated = false;
        }
        Dispatcher.Invoke(() => UpdateStatus("任务已取消"));
    }
    finally
    {
        _pauseEvent.Reset();
    }
}

文件生成函数实现

每个生成函数中加入暂停检查和取消检查,确保线程安全:

private async Task GenerateFile1Async(CancellationToken token)
{
    lock (_statusLock)
    {
        if (_isFile1Generated) return;
    }
    
    // 先检查取消信号
    token.ThrowIfCancellationRequested();
    // 检查是否需要暂停,同时响应取消信号
    _pauseEvent.Wait(token);
    
    try
    {
        // 替换为实际文件生成逻辑,这里用延迟模拟
        await Task.Delay(2000, token);
        lock (_statusLock)
        {
            _isFile1Generated = true;
        }
        Dispatcher.Invoke(() => UpdateStatus("文件1生成完成"));
    }
    catch (OperationCanceledException)
    {
        lock (_statusLock)
        {
            _isFile1Generated = false;
        }
        throw; // 向上抛出异常,让任务捕获并处理
    }
}

// GenerateFile2Async、GenerateFile3Async逻辑与上述一致,仅替换对应状态变量即可

中止按钮点击事件处理

点击按钮时先暂停任务,弹出确认框后再决定取消或恢复:

private void AbortButton_Click(object sender, RoutedEventArgs e)
{
    if (_fileGenerationTask == null || _fileGenerationTask.IsCompleted)
        return;
    
    // 暂停任务:重置信号,让后台任务进入等待状态
    _pauseEvent.Reset();
    
    // 弹出确认对话框(UI线程执行,后台任务此时已暂停)
    var result = MessageBox.Show("确定要中止文件生成吗?", "确认中止", MessageBoxButton.YesNo);
    if (result == MessageBoxResult.Yes)
    {
        // 用户确认,触发任务取消
        _cts.Cancel();
        // 等待任务完成(可选,根据需求决定是否等待)
        _fileGenerationTask.Wait();
        // 关闭窗口或更新UI
        Close();
    }
    else
    {
        // 用户取消,恢复任务执行
        _pauseEvent.Set();
        Dispatcher.Invoke(() => UpdateStatus("任务已恢复"));
    }
}

初始化与资源清理

在窗口生命周期中初始化和清理资源:

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    _cts = new CancellationTokenSource();
    _pauseEvent = new ManualResetEventSlim(true); // 初始状态不暂停
    _fileGenerationTask = StartFileGenerationAsync();
}

private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
    // 确保任务被取消并释放资源
    _cts?.Cancel();
    _fileGenerationTask?.Wait();
    _cts?.Dispose();
    _pauseEvent?.Dispose();
}

关键说明

  • 线程安全:用lock保护文件状态变量,ManualResetEventSlim是线程安全的同步原语,避免多线程冲突
  • 暂停逻辑:_pauseEvent.Reset()会让后台任务在Wait()处阻塞,直到调用Set()恢复执行
  • 取消逻辑:CancellationToken贯穿任务全流程,确保取消信号能被及时响应
  • UI交互:弹窗在UI线程执行,后台任务此时处于暂停状态,不会继续生成文件

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 01:30:55