对于初始化一次且长度不变的集合的System.IndexOutOfRangeException如何?

时间:2012-07-02 17:51:00

标签: c#

我无法理解为什么我今天收到System.IndexOutOfRangeException。我已经在程序工作8小时后收到它,并且异常发生的地方被执行了数百万次。这个地方很简单:

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()

4 个答案:

答案 0 :(得分:2)

来自System.Array on MSDN

  

不保证所有实例成员都是线程安全的。

通过在多个线程之间共享此数组实例,您将违反文档。你应该正确锁定。

答案 1 :(得分:1)

Imo 问题是你有几个函数接受像int index这样的参数(或类似的东西)并使用该参数从数组中恢复数据。

数组的大小没有改变,没关系。但即使您的数组长度是静态的并且等于(比如说)5,如果您尝试使用index>=5访问该数组,您将获得所描述的异常。

编辑

考虑到在for(...)循环中引发异常的另一种可能性,其中的边界用数组本身的大小标记,我会说考虑执行堆栈,你在 parallel中执行东西。所以,我假设此时数组的大小以某种方式发生变化。

要检查此项,您可以尝试执行以下操作:

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

并检查错误是否仍然存在。

希望这有帮助。

答案 2 :(得分: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是一个有效的输出

答案 3 :(得分: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; 
}