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])));
}