2010-09-25 52 views
11

我們在生產環境中遇到了奇怪的錯誤,我們無法調試也無法注入日誌記錄代碼。我試圖找出這個,但下面的堆棧跟蹤混淆了我。在什麼情況下System.Collections.ArrayList.Add拋出IndexOutOfRangeException?

System.IndexOutOfRangeException: Index was outside the bounds of the array. 
    at System.Collections.ArrayList.Add(Object value) 
    at ... 

According to the MSDNAdd方法時才拋出NotSupportedException

我不知道這裏發生了什麼。你做?

+0

你可以發佈一些完整的stacktrace嗎? – shahkalpesh 2010-09-25 14:25:05

+3

只是猜測:ArrayList用於多線程操作? – 2010-09-25 14:28:28

+0

您可能能夠通過在發生異常時在調試器中檢查其他線程狀態來確認併發錯誤。檢查當時是否有其他人正在更換容器。 – 2010-09-25 15:47:59

回答

7

它歸結爲列舉不是線程安全的。在一個列表迭代使用多線程添加項目沒有下文同步,

List<TradeFillInfo> updatedFills = new List<TradeFillInfo>(); 
Parallel.ForEach (trades, (trade) => 
{ 
    TradeFillInfo fill = new TradeFillInfo(); 

    //do something 

    updatedFills.Add(fill); //NOTE:Adding items without synchronization 
}); 

foreach (var fill in updatedFills) //IndexOutOfRangeException here sometimes 
{ 
    //do something 
} 

時,在這種情況下,我不得不IndexOutOfRangeException發生的歷史,updatedFills算遭破壞,後續迭代失敗。圍繞鎖定語句包裝Add()應該可以避免這種情況。

lock (updatedFills) 
{ 
    updatedFills.Add(fill); 
} 
19

當「嘗試訪問數組元素的索引超出數組邊界的數組元素時,會引發IndexOutOfRangeException」。

請注意,ArrayList類不是線程安全的。在多線程場景中,競爭條件可能會導致ArrayList試圖讀取/寫入超出其範圍的索引處的支持數組。

示例:一個線程在另一個線程添加到集合的同時,減少了後備陣列的大小(可能通過調用TrimToSize)。現在,如果後備數組處於滿負荷狀態,則添加線程將嘗試擴展其容量(通過分配新數組)以容納新元素。同時TrimToSize調用然後反轉這種效果。然後,當添加線程嘗試寫入數組時,其認爲可用的索引將不再存在,從而導致拋出異常。

修復:使用線程安全結構,適合您的的情況。

11

這幾乎可以肯定是一個併發問題......您可能有兩個線程同時修改集合,並且ArrayList類不支持併發訪問。發生競態條件,這有時會導致其中一個線程嘗試寫入數組邊界之外的位置。

盡力保護所有使用lock語句訪問集合,或使用回收的同步包裝(使用ArrayList.Synchronized法)

相關問題