C# 从并发字典中删除元素时并行任务执行的不同行为

C# 从并发字典中删除元素时并行任务执行的不同行为,c#,multithreading,concurrency,thread-safety,task,C#,Multithreading,Concurrency,Thread Safety,Task,我想测试并行添加和删除到并发字典。 我的测试类中有以下代码: [TestMethod] public void T_Parallel_Removing { var management = new Management(); List<Task> AddTasks = new List<Task>(); List<Task> RemoveTasks = new List<Task>(

我想测试并行添加和删除到并发字典。 我的测试类中有以下代码:

[TestMethod]
    public void T_Parallel_Removing
    {
        var management = new Management();

        List<Task> AddTasks = new List<Task>();
        List<Task> RemoveTasks = new List<Task>();

        var units = new List<Unit>();

        for (int i = 0; i < 30; i++)
        {
            var unit= = new Unit();
            units.Add(unit);
            AddTasks.Add(Task.Run(() => AddUnit(management, unit)));
        }

        Task.WaitAll(AddTasks.ToArray());
    }
这个很好用。但是当我开始删除一些奇怪的东西时(忽略int区域,我不知何故认为它们是问题的一部分,但事实并非如此)

它毫无问题地工作。如果我在for循环中添加一些伪代码或Thread.Sleep(1),它也可以工作(每个任务都有不同的地址)

有人能解释一下这种行为吗?

for(int i=0;i<29;i++)
for (int i = 0; i < 29; i++)
{
  RemoveTakes.Add(Task.Run(() => RemoveUnit(management, units[i])));
}
{ RemoveTakes.Add(Task.Run(()=>RemoveUnit(management,units[i])); }
不会做你认为它会做的事

您应该将其更改为:

for (int i = 0; i < 29; i++)
{
  var bob = i;
  RemoveTakes.Add(Task.Run(() => RemoveUnit(management, units[bob])));
}
for(int i=0;i<29;i++)
{
var-bob=i;
RemoveTakes.Add(Task.Run(()=>RemoveUnit(management,units[bob]));
}
对于原始代码,当
任务运行时,
i
的值已更改。因此,您需要将其存储在一个单独的变量中(
bob
-作用域在循环内),以便第一个
任务
获取
0
,下一个获取
1

您的问题基本上与相同(尽管它使用的是
foreach
原则是相同的)


请注意,如果您安装了Resharper,它应该会有此问题。

如果您更改
任务,请运行(()=>RemoveUnit(管理,units[i])
任务。运行(()=>Console.WriteLine(i))
控制台中写入了什么?这就是您所期望的吗?不知道循环中几乎任何lambda=。每次运行后bob不会被销毁吗?不,
bob
将保持活动状态,直到不再“需要”(闭包就是这样工作的)。实际上,这是当
RemoveUnit
完成执行时。
RemoveTakes.Add(Task.Run(() => RemoveUnit(management, units[0])));
         RemoveTasks .Add(Task.Run(() => RemoveUnit(management, units[1])));
         RemoveTasks .Add(Task.Run(() => RemoveUnit(management, units[2])));
         RemoveTasks .Add(Task.Run(() => RemoveUnit(management, units[3])));
         RemoveTasks .Add(Task.Run(() => RemoveUnit(management, units[4])));
         RemoveTasks .Add(Task.Run(() => RemoveUnit(management, units[5])));
for (int i = 0; i < 29; i++)
{
  RemoveTakes.Add(Task.Run(() => RemoveUnit(management, units[i])));
}
for (int i = 0; i < 29; i++)
{
  var bob = i;
  RemoveTakes.Add(Task.Run(() => RemoveUnit(management, units[bob])));
}