2016-05-17 28 views
0

我有一個靜態數組變量正在由兩個線程共享。一個線程可以改變引用到另一個線程迭代通過它

我想知道,如果我指定數組變量另一個數組對象Thread1Thread2迭代是在陣列上會發生什麼。

在線程1

MyStaticClass.MyArray = SomeOtherArray 

在線程2:

for (int i = 0; i < MyStaticClass.MyArray.length; i++) 
{ 
    //do something with the i'th element 
} 
+0

結果不容易預測。它可能會繼續迭代正常(儘管顯然交換在循環中使用的變量可能是*不好*)。如果您嘗試使用現在大於數組長度的索引,它可能會崩潰。這種類型的代碼將是非常糟糕的形式,並且是鎖被髮明的原因。一般來說,多線程的最佳經驗法則是避免在線程之間共享數據,並始終鎖定您分享的內容。 –

回答

1

假設MyStaticClass.MyArray僅僅是一個字段或簡單的屬性。

沒有什麼好的或可以預測的,這是肯定的。

我會說最有可能的是:

  • 環可以讀取舊陣列的一半,距離新的數組休息
  • 新陣列可能會比過去的短,當你訪問給人一種異常[i]
  • 線程2可能實際上完全忽略了對數組的更改!更糟糕的是,這種行爲在Release版本中可能與Debug不同。

最後一種情況是由於編譯器的優化和/或存儲模式工作在.NET(和其他語言如Java BTW)的方式。有一個完整的關鍵字來解決此問題(volatilehttp://igoro.com/archive/volatile-keyword-in-c-memory-model-explained/

1

爲了防止這種情況,你想用鎖鎖住臨界區。基本上在鎖包裹你的itteration可以阻止其它線程覆蓋數組,而你正在處理它

lock關鍵字可確保在另一個線程處於臨界區一個線程不會進入代碼的臨界段。如果另一個線程嘗試輸入一個鎖定的代碼,它將等待,阻止,直到該對象被釋放。

https://msdn.microsoft.com/en-us/library/c5kehkcz.aspx

1

您的for循環中的條件將針對每次迭代進行評估。因此,如果另一個線程更改了MyStaticClass.MyArray中的引用,則可在下一次迭代中使用此新引用。

例如,下面的代碼:

int[] a = {1,2,3,4,5}; 
int[] b = {10, 20, 30, 40, 50, 60, 70}; 

for (int i = 0; i < a.Length; i++) 
{ 
    Console.WriteLine(a[i]); 
    a = b; 
} 

給出了這樣的輸出:

1 
20 
30 
40 
50 
60 
70 

爲了避免這種情況,你可以使用foreach

foreach(int c in a) 
{ 
    Console.WriteLine(c); 
    a = b; 
} 

給出:

1 
2 
3 
4 
5 

因爲foreach翻譯,使其調用a.GetEnumerator()一次,然後使用這個枚舉(MoveNext()Current)的各個版本,而不是再次訪問a

+0

嗯是一個完整的原子迭代保證之前交換將發生?由於您在單個線程中迭代它的順序執行。對我而言,這可能並非如此。 – user2635088

+0

@ user2635088否(儘管我不知道_atomic_迭代可能是什麼)。如果另一個線程在迭代線程離開「for」行後立即更改了「MyArray」,那麼在循環內部,您已經訪問了新的數組引用。如果新數組小於當前索引「i」,這可能已經導致「IndexOutOfRangeException」。 –

+0

@ user2635088爲了簡單起見,我只使用了一個單線程示例。我只想表明'for'循環在每次訪問這個變量時都計算'MyArray',並且不會緩存它。所以你應該避免在迭代時在另一個線程中改變它。 –

0

除了線程2之外,在開始使用新數組而不是舊線程的某個時刻,不會有任何後果。當這種情況發生時或多或少是隨機的,正如韋斯頓在他的評論中寫道的那樣,它甚至可能永遠不會發生。

如果新數組的元素少於舊數組,則可以(但不一定)會導致運行時異常。

+0

你不能保證線程2 *將永遠*在新陣列上工作。請閱讀.net http://igoro.com/archive/volatile-keyword-in-c-memory-model-explained/中的內存模型 – weston

相關問題