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

使用SemaphoreSlim限制C#并行任务数量时触发ObjectDisposedException异常的问题排查与解决

问题根源分析

你遇到的ObjectDisposedException主要有两个核心原因:

  1. 任务数组中存在未初始化的null元素
    你的taskArray是按recorder.Channels.Count固定长度创建的,但只有当test(channel.Name)返回true时才会赋值任务并递增index。这意味着数组中会存在大量null值,当调用Task.WaitAll(taskArray)时,会触发ArgumentException(因为不允许等待null任务)。这个未被捕获的异常会直接让程序退出using块,导致SemaphoreSlim被提前释放(Dispose)。而此时正在运行的任务在finally块中调用concurrencySemaphore.Release()时,就会触发ObjectDisposedException。

  2. 迭代变量捕获的潜在问题
    在foreach循环中直接捕获channel变量,在C# 5之前的版本中,迭代变量是在循环外部声明的,所有任务会共享同一个引用,导致所有任务处理的都是最后一个IDataChannel实例。虽然这不是当前异常的直接原因,但会导致业务逻辑错误,必须提前修复。


修复后的代码示例
int maxTasks = 2;
using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(maxTasks))
{
    // 用动态列表存储实际要执行的任务,避免null元素
    List<Task<int>> tasks = new List<Task<int>>();
    
    foreach (IDataChannel channel in recorder.Channels)
    {
        if (test(channel.Name))
        {
            concurrencySemaphore.Wait();
            
            // 创建局部变量捕获当前channel,避免引用共享问题
            IDataChannel currentChannel = channel;
            
            Task<int> task = Task<int>.Factory.StartNew(() =>
            {
                int resTask = -1;
                try
                {
                    resTask = ProcessChannel(currentChannel, id, filename, recorder.Name);
                }
                finally
                {
                    // 确保信号量一定会被释放,即使任务执行失败
                    concurrencySemaphore.Release();
                }
                return resTask;
            });
            
            tasks.Add(task);
        }
    }
    
    // 只等待实际创建的任务,避免null导致的异常
    Task.WaitAll(tasks.ToArray());
}

// 处理任务结果
int res = 0;
foreach (var task in tasks)
{
    int result = task.Result;
    if (result == -1)
    {
        res = -1;
        break;
    }
}

额外优化建议
  1. 优先使用异步等待:如果你的代码运行在异步方法中,建议用await Task.WhenAll(tasks)代替Task.WaitAll,避免阻塞主线程,提升程序响应性。
  2. 添加等待超时机制:可以给SemaphoreSlim.Wait()添加超时时间,比如concurrencySemaphore.Wait(TimeSpan.FromSeconds(30)),避免主线程无限等待。异步场景下可以用await concurrencySemaphore.WaitAsync(TimeSpan.FromSeconds(30))。
  3. 异常处理增强:可以在任务内部添加更详细的异常捕获逻辑,方便排查ProcessChannel方法中可能出现的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 07:47:29