2017-09-14 24 views
-1

我想測試並行添加和刪除到並行字典。 我有下面的代碼在我的測試類:從並行字典中刪除元素的並行任務執行的不同行爲

[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()); 
    } 

的添加刪除UND方法:

public void AddUnit(Management m, Unit u,) 
    { 
     management .AddPlantUnit(u, "",); 
    } 


    public void RemoveUnit(Management m, Unit u) 
    { 
     m.RemovePlantUnit(u.Adress); 
     Console.WriteLine(u.Adress); 
    } 

這工作完全正常。但是,當我開始刪除一些奇怪的情況發生(忽略整型領域,我總覺得他們是問題的一部分,但他們都沒有)

for (int i = 0; i < 29; i++) 
     { 
      RemoveTasks .Add(Task.Run(() => RemoveUnit(management, units[i]))); 

     } 

在這裏,我總是得到同一個地址和輸出如果每個任務都一樣。

但是,如果使用下面的代碼:

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循環中添加一些虛擬代碼或Thread.Sleep(1),它也可以工作(每個任務獲得不同的地址)

有人可以解釋這種行爲嗎?

+0

如果將Task.Run(()=> RemoveUnit(management,units [i]))''改成Task.Run(()=> Console.WriteLine(i))'寫入的內容安慰?這是你的預期嗎? – mjwills

+0

不知道[閉包](https://stackoverflow.com/q/428617/1997232)幾乎任何lambda在循環= [問題](https://stackoverflow.com/q/16264289/1997232)。 – Sinatr

回答

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

隨着你的原代碼,由當時​​的Task跑的i值發生了變化。所以,你需要存儲在一個單獨的變量(bob - 範圍的內循環),從而第一Task得到0,下得1

你的問題是基本相同this one(儘管它使用foreach原理是一樣的)。

請注意,如果您安裝了Resharper,它應該有highlighted這個問題給你。

+0

每次運行後都不會被破壞? – Rolfant90

+0

不,'bob'會一直活着,直到它不再'需要'(這就是封閉如何工作)。實際上,這是'RemoveUnit'完成執行時的情況。 – mjwills