任务完成并出现 ObjectDisposed 异常

Tasks finished with ObjectDisposed exception

我完成了一份兼顾多项工作的工作。我为每个作业启动一个任务,但我必须限制并行 运行ning 的任务数量。我已经按照 post .

中解释的方法进行操作

在我的示例中,我必须 运行 4 个作业,但一次只能处理 2 个。问题是当前 2 个作业结束时,抛出 ObjectDisposed 异常并且程序结束。目标是在检查结果之前继续挂起的任务。

这是 运行 的代码片段,等待并获取结果:

Task<int>[] taskArray = new Task<int>[recorder.Channels.Count];
//recorder.Channels.Count is 4
int index = 0;
int maxTasks = 2;

using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(maxTasks))
{
    foreach (IDataChannel channel in recorder.Channels)
    {
        if (test(channel.Name))
        {
            concurrencySemaphore.Wait();
            taskArray[index] = Task<int>.Factory.StartNew(() =>
            {
                int resTask = -1;
                try
                {
                    resTask = ProcessChannel(channel, id, filename, recorder.Name);
                }
                finally
                {
                    concurrencySemaphore.Release();
                }
                return resTask;
            });
            index++;
        }
    }
    Task.WaitAll(taskArray);
}

// Check for task results
int[] results = new int[taskArray.Length];

for (int i = 0; i < taskArray.Length; i++)
{
    results[i] = taskArray[i].Result;
    if (results[i] == -1)
    {
        res = -1;
        break;
    }
}

我觉得有些地方我不明白。所以如果有人能帮助我,我将不胜感激。

好的,我试着在这里提出一个解决方案。如果:if (test(channel.Name)) 曾经 returns false,那么您基本上就是一个大问题。因为那时 Task.WaitAll(taskArray); 会抛出 ArgumentException,因为它不喜欢数组中的 null 值。

第二个是race condition,基本上是特定情况下的跟进问题。仅当数组中第二个 Task 的位置为 null 时才会抛出 objectDisposed 异常。如果我将 test 编程为 return 总是 true 永远不会抛出异常。

想象一下以下场景:

  1. test returns TRUE 并且 Task_1 已创建并开始 运行

  2. 然后在下一次迭代中 test returns FALSE 并且没有创建 Task 但循环继续 运行。所以现在数组中只有3个地方可以填充。基本上它将最后一个值保留为 null

  3. 现在在第 3 次和 4.th 迭代测试再次 returns TRUE 并且 Task_2 和 Task_3 被创建并开始 运行.

  4. 当所有任务都被创建并且循环结束时,你来到 Task.WaitAll(taskArray); 所在的位置并开始等待,不幸的是它立即异常退出,因为有 null 数组中的值。所以编译器离开了 using 块!从而处理信号量!!

  5. 但是你还有任务运行!当这个任务到达终点时:concurrencySemaphore.Release(); 信号量早已消失并被处置,因为 test 方法搞砸了你的算法!

所以我建议使用动态增长的集合,例如:

List<Task<int>> taskArray = new List<Task<int>>(4); 

然后只需将每个新任务添加到列表中即可:

taskArray.Add(Task<int>.Factory.StartNew(() => 

最后你将列表转换为数组以满足WaitAll方法:

Task.WaitAll(taskArray.ToArray());

在我的示例中,异常现已消失