2012-07-02 95 views
1

我不明白爲什麼我今天收到System.IndexOutOfRangeException。我已經收到它,當程序已經工作了8個小時,發生異常的地方被執行了數百萬次。這個地方是非常簡單的:System.IndexOutOfRangeException初始化一次,長度不變的集合,如何?

for (int i = 0; i < _goldDesiredOrdersBuy.Length; i++) 
{ 
    _goldDesiredOrdersBuy[i] = -1;    // IndexOutOfRangeException! Strategy3.cs:line 666 
} 

我初始化_goldDesiredOrdersBuy只有當程序啓動,所以它保證,當出現異常它初始化一次:

private int[] _goldDesiredOrdersBuy = new int[MaxOrderbookDepth]; 

我有一個另一個地方,我接觸這個數組:

private int GetGoldVolumeBuy(int bidQuotesPos) 
    { 
     if (_goldDesiredOrdersBuy[bidQuotesPos] > -1) 
     { 
      return _goldDesiredOrdersBuy[bidQuotesPos]; 
     } 
     int result = GetGoldVolumeBuyNotCached(bidQuotesPos); 
     _goldDesiredOrdersBuy[bidQuotesPos] = result; 
     return result; 
    } 

而就是這樣。 _goldDesiredOrdersBuy在應用程序啓動時初始化一次,保證初始化並且數組的長度不會在任何地方修改,所以我不明白我是如何收到IndexOutOfRangeException的,有什麼想法?

Unhandled Exception: System.AggregateException: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread. ---> 
    System.AggregateException: One or more errors occurred. ---> 
    System.IndexOutOfRangeException: Index was outside the bounds of the array. 
    at MyProj.Strategies.Strategy3.CalculateNewDesiredOrdersBuy() in C:\Oleg\projects\MyProj\MyProj\Strategies\Strategy3.cs:line 666 
    at MyProj.Strategies.Strategy3.RecalculateBuyOrders() in C:\Oleg\projects\MyProj\MyProj\Strategies\Strategy3.cs:line 567 
    at MyProj.Strategies.Strategy3.OnAllTablesUpdated() in C:\Oleg\projects\MyProj\MyProj\Strategies\Strategy3.cs:line 499 
    at MyProj.Strategies.Strategy3.AllTablesUpdated() in C:\Oleg\projects\MyProj\MyProj\Strategies\Strategy3.cs:line 413 
    at System.Threading.Tasks.Parallel.<>c__DisplayClassf`1.<ForWorker>b__c() 
    at System.Threading.Tasks.Task.InnerInvokeWithArg(Task childTask) 
    at System.Threading.Tasks.Task.<>c__DisplayClass7.<ExecuteSelfReplicating>b__6(Object) 
    --- End of inner exception stack trace --- 
    at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken) 
    at System.Threading.Tasks.Task.Wait() 
    at System.Threading.Tasks.Parallel.ForWorker[TLocal](Int32 fromInclusive, Int32 toExclusive, ParallelOptions parallelOptions, Action`1 body, Action`2 bodyWithState, Func`4 bodyWithLocal, Func`1 localInit, Action`1 localFinally) 
    at System.Threading.Tasks.Parallel.ForEachWorker[TSource,TLocal](IEnumerable`1 source, ParallelOptions parallelOptions, Action`1 body, Action`2 bodyWithState, Action`3 bodyWithStateAndIndex, Func`4 bodyWithStateAndLocal, Func`5 bodyWithEverything, Func`1 localInit, Action`1 localFinally) 
    at System.Threading.Tasks.Parallel.ForEach[TSource](IEnumerable`1 source, Action`1 body) 
    at MyProj.Market.FinishUpdatingTables() in C:\Oleg\projects\MyProj\MyProj\Market.cs:line 449 
    at Library.Exchange.Gate.DoGateIteration() in C:\Oleg\projects\MyProj\MyProj\Gate.cs:line 143 
    at Library.Exchange.Gate.<Connect>b__0() in C:\Oleg\projects\MyProj\MyProj\Gate.cs:line 98 
    at System.Threading.Tasks.Task.Execute() 
    --- End of inner exception stack trace --- 
    at System.Threading.Tasks.TaskExceptionHolder.Finalize() 

回答

0

那麼,這種方法不檢查傳入的有效指標。
所以我會盡量把一些安全檢查在這裏。

private int GetGoldVolumeBuy(int bidQuotesPos) 
{ 
    int result = -1; 
    if(bidQuotesPos >= 0 && bidQuotesPos < _goldDesiredOrdersBuy.Length) 
    { 
     if (_goldDesiredOrdersBuy[bidQuotesPos] > -1) 
     { 
      return _goldDesiredOrdersBuy[bidQuotesPos]; 
     } 
     result = GetGoldVolumeBuyNotCached(bidQuotesPos); 
     _goldDesiredOrdersBuy[bidQuotesPos] = result; 
    } 
    return result; 
} 

我假設result=-1這裏是一個有效的輸出

+0

請注意,該程序的不同部分發生異常。在非常微不足道的部分。 – javapowered

+0

我們正面臨不可能的情況。因此,可用信息中的某些內容可能是錯誤的。我懷疑堆棧跟蹤的有效性(也給出了並行執行)。我仍然賭上一個明顯的地方。 – Steve

+0

我明白了。那麼現在我包圍了發生異常的地方來捕獲它並打印更多的調試信息。 – javapowered

1

伊莫的問題是,你有幾個函數接受像int index(或類似的東西)的參數,並使用該參數來恢復數組中的數據。

數組的大小沒有改變,沒關係。但是即使你的數組​​長度是靜態的並且等於(比如說)5,如果你將嘗試使用index>=5訪問該數組,你將得到你所描述的異常。

編輯

考慮到例外另一種可能性是for(...)循環中提出,其中的界限都標有陣列本身的大小,我要說的是,考慮到執行堆棧,你並行執行的東西。所以,我假設在這一點上,數組的大小以某種方式改變。

要檢查這一點,你可以嘗試做如下:

int limit = _goldDesiredOrdersBuy.Length; //SET LIMIT BEFORE ITERATION 
for (int i = 0; i < limit ; i++) 
{ 
    _goldDesiredOrdersBuy[i] = -1;   
} 

,並檢查錯誤仍然發生。

希望這會有所幫助。

+0

我在我的程序的一部分初始化'_goldDesiredOrdersBuy'。在只在程序啓動時調用的類的構造函數中。所以我不明白'_goldDesiredOrdersBuy'的尺寸可以改變。可能我應該捕捉到這個異常並打印更多的跟蹤信息(數組長度等),然後重新拋出不要隱藏問題 – javapowered

0

您不檢查bidQuotesPos的值是否在數組範圍內。

private int GetGoldVolumeBuy(int bidQuotesPos) 
{ 
    if (bidQuotesPos < 0 || bidQuotesPos >= _goldDesiredOrdersBuy.Length) 
    { 
     // either throw an exception, or (less desireable) return a value so that the caller 
     // knows that an error occurred. 
     return HandleInvalidInputValue(bidQuotesPos); 
    } 

    if (_goldDesiredOrdersBuy[bidQuotesPos] > -1) 
    { 
     return _goldDesiredOrdersBuy[bidQuotesPos]; 
    } 
    int result = GetGoldVolumeBuyNotCached(bidQuotesPos); 
    _goldDesiredOrdersBuy[bidQuotesPos] = result; 
    return result; 
} 
+0

注意異常發生在程序的不同部分。在非常微不足道的部分。儘管你的建議可能有用,但它與我的問題無關,因爲它不是我在Strategy3.cs中收到的異常:第666行 – javapowered

2

System.Array on MSDN

所有實例成員不能保證線程安全的。

通過在多個線程之間共享此數組實例,您將違反文檔。你應該正確鎖定。

+0

我不在多個線程中共享'_goldDesiredOrdersBuy',至少我不打算這樣做。在paralellel foreach中,每個線程都有自己的'_goldDesiredOrdersBuy'成員 – javapowered

+0

實際上'_goldDesiredOrdersBuy'是從不同的線程訪問的。但同時'_goldDesiredOrdersBuy'總是隻能從一個線程訪問。即每次執行並行foreach時,我都有可能創建新線程,但在完成之前,我總是執行新的並行foreach。 – javapowered