2015-12-17 109 views
1

我正在學習在C#中使用任務並行庫(TPL),並編寫了下面的代碼(可以複製它並運行它)。爲什麼工廠循環打印超出循環索引?

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Threading.Tasks; 

namespace parallelTaskLibrary 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      for (int i = 0; i < 6; i++) 
      { 
       var t01 = Task.Factory.StartNew(() => Console.WriteLine("in loop: i = {0}", i)); 
      } 

      Console.WriteLine("press any key to terminate..."); 
      Console.ReadKey(); 
     }  
    } 
} 

for迴路,計數器索引i不能與i = 6一個值開始迭代。但是,我得到的輸出是這樣的:

press any key to terminate... 
in loop: i = 6 
in loop: i = 6 
in loop: i = 6 
in loop: i = 6 
in loop: i = 6 
in loop: i = 6 

然而,在另一上市(代碼並沒有改變),我得到這個:

in loop: i = 1 
in loop: i = 1 
in loop: i = 2 
in loop: i = 3 
in loop: i = 4 
in loop: i = 5 
press any key to terminate... 

這是合理的......

我調試的代碼,並發現i值是:0,1,3,4,5,6

如何發生的呢?

爲什麼我在循環中得到(i = 6)?

我的代碼有什麼問題嗎?

注:我使用Visual Studio 2010

回答

10

因爲有一個封閉的問題。您需要將變量i複製到臨時變量中。

for (int i = 0; i < 6; i++) 
{ 
    var tempi = i; 
    var t01 = Task.Factory.StartNew(() => Console.WriteLine("in loop: i = {0}", tempi)); 
} 

因爲你的任務開始在另一個線程。但是你不會在當前線程中等待這個任務。所以程序會回來並增加計數器。由於您創建的代表使用原始計數器,因此它會打印6。因爲計數到6比創建新任務要快得多。

當您使用調試器的新任務將有機會你繼續增加計數器之前打印的價值,

1

顯然,你將打印的值「i」作爲執行代碼(與Console.WriteLine命令語句委託),當它是,這很可能在稍晚的時間

這是probaby你想要什麼:

for (int i = 0; i < 6; i++) 
{ 
    var j = i; 
    var t01 = Task.Factory.StartNew(() => Console.WriteLine("in loop: i = {0}", j)); 
} 

>是有什麼錯在我的代碼?

是:-)

1

與該代碼你對你有什麼要注意工作示例在編程時multi-threaded-applications。問題是啓動一個需要一些時間,在這段時間主線程完成迭代通過for-loop。當主線程完成i == 6並且每個線程訪問值爲i這是6。一個解決辦法是讓一個局部變量和複製的i

for(...) 
{ 
    int temp = i; 
    var t1 //..... 
} 
2
for (int i = 0; i < 6; i++) 

從C#2012下面的代碼將工作啓動值按預期:

foreach (int i in Enumerable.Range(0, 6)) 

http://ideone.com/naaZNx - 例如。

聲明循環內部的變量是breaking changes in VS2012之一。

+0

@HansKesting,我知道:

Console.WriteLine("press any key to terminate..."); 

創建執行所有6個線程關於這個問題。而foreach將在裏面聲明變量。請閱讀[打破VS2012的更改](https://msdn.microsoft.com/en-us/library/hh678682(v = vs.110).aspx)。 – Qwertiy

+0

你說得對,我忘記了。您可能需要在您的答案中添加展開內容。 –

+0

你是對的,但確實有效,但是,我在操作系統層面尋找原因。 – ThunderWiring

0

爲什麼我在循環中得到(i = 6)?

所有以下步驟:

i=0 
i<6 => create Thread1 
i++ => i=1 
i<6 => create Thread2 
i++ => i=2 
i<6 => create Thread3 
i++ => i=3 
i<6 => create Thread4 
i++ => i=4 
i<6 => create Thread5 
i++ => i=5 
i<6 => create Thread6 
i++ => i=6 
i<6 NO => leave for 

主線程執行: Console.WriteLine("in loop: i = {0}", i)其中I = 6