任务完成并出现 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
永远不会抛出异常。
想象一下以下场景:
test
returns TRUE 并且 Task_1 已创建并开始 运行
然后在下一次迭代中 test
returns FALSE 并且没有创建 Task
但循环继续 运行。所以现在数组中只有3个地方可以填充。基本上它将最后一个值保留为 null
现在在第 3 次和 4.th 迭代测试再次 returns TRUE 并且 Task_2 和 Task_3 被创建并开始 运行.
当所有任务都被创建并且循环结束时,你来到 Task.WaitAll(taskArray);
所在的位置并开始等待,不幸的是它立即异常退出,因为有 null
数组中的值。所以编译器离开了 using 块!从而处理信号量!!
但是你还有任务运行!当这个任务到达终点时:concurrencySemaphore.Release();
信号量早已消失并被处置,因为 test
方法搞砸了你的算法!
所以我建议使用动态增长的集合,例如:
List<Task<int>> taskArray = new List<Task<int>>(4);
然后只需将每个新任务添加到列表中即可:
taskArray.Add(Task<int>.Factory.StartNew(() =>
最后你将列表转换为数组以满足WaitAll
方法:
Task.WaitAll(taskArray.ToArray());
在我的示例中,异常现已消失
我完成了一份兼顾多项工作的工作。我为每个作业启动一个任务,但我必须限制并行 运行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
永远不会抛出异常。
想象一下以下场景:
test
returns TRUE 并且 Task_1 已创建并开始 运行然后在下一次迭代中
test
returns FALSE 并且没有创建Task
但循环继续 运行。所以现在数组中只有3个地方可以填充。基本上它将最后一个值保留为null
现在在第 3 次和 4.th 迭代测试再次 returns TRUE 并且 Task_2 和 Task_3 被创建并开始 运行.
当所有任务都被创建并且循环结束时,你来到
Task.WaitAll(taskArray);
所在的位置并开始等待,不幸的是它立即异常退出,因为有null
数组中的值。所以编译器离开了 using 块!从而处理信号量!!但是你还有任务运行!当这个任务到达终点时:
concurrencySemaphore.Release();
信号量早已消失并被处置,因为test
方法搞砸了你的算法!
所以我建议使用动态增长的集合,例如:
List<Task<int>> taskArray = new List<Task<int>>(4);
然后只需将每个新任务添加到列表中即可:
taskArray.Add(Task<int>.Factory.StartNew(() =>
最后你将列表转换为数组以满足WaitAll
方法:
Task.WaitAll(taskArray.ToArray());
在我的示例中,异常现已消失