title: Task.Run does unexpected things
body: <p>I'm stumped... I'm trying to get the hang of splitting up calculations in tasks to speed up the program. That seems to work fine for small pieces of code, but I'm failing miserably when it gets a little more difficult.</p>
  <p>Situation:
  I have a program that calculates about 1,000 factors in a 5-step process for each factor. I want to split the calculation of those factors up into tasks.</p>
  <p>The code that does the trick (but without using Tasks):</p>
  <pre><code>Public Overridable Function GetFactor(Gender As Short, Age As Short) As Double Implements IFactor.GetFactor
      'Set up the Markov Chain associated with a factor
      Me.Markov = New MarkovChain(Gender, Age)
  
      'Set up the payment schedule
      Me.Payments = New PaymentsAnnuity(Age, Me.MaxAge)
  
      'Determine the benefits
      Me.Benefits = New Benefit(Age, Me.MaxAge)
  
      'Calculate the cash flows
      Call Me.CalcCashFlow()
  
      'Calculate the factor and return it
      Return Me.CalcFactor()
  End Function
  </code></pre>
  <p>That code works fine for one factor. I then have a calculation engine that iterates through all factors and ages</p>
  <pre><code>Public Sub RunCalculations(ByVal MinAge As Short, ByVal MaxAge As Short)
      'Cycle through all available factors
      For iParam As Integer = 0 To Me.Factors.Length - 1
          'Fetch the new factor specific parameter set
          Dim Param As FactorParameters = Me.Factors(iParam)
  
          'Get a new factor generator of the proper kind. Note that all generators are stored in their corresponding
          'FactorParameters &quot;FactorType&quot; value upon creation of the Calculation Engine to allow for easy selection
          Dim Generator As IFactor = Me.Generators(Param.FactorType).GetInstance(Me.Assumptions, Param)
  
          'Calculate the factors for both males and females and store them in the Output matrices
          For iAge As Short = MinAge To MaxAge
              Me.OutputResultsMale(iAge - MinAge, iParam + 1) = Generator.GetFactor(0, iAge)
              Me.OutputResultsFemale(iAge - MinAge, iParam + 1) = Generator.GetFactor(1, iAge)
          Next iAge
      Next iParam
  End Sub
  </code></pre>
  <p>The above code runs fine and I get all the factors I asked for, but it takes ages. I therefore tried to generate tasks, one for each factor and have it run on multiple cores. I changed the code in the Sub RunCalculations (most notably the iAge For-loop):</p>
  <pre><code>Public Sub RunCalculations(ByVal MinAge As Short, ByVal MaxAge As Short)
      'Set up Task matrices to populate the output matrices
      Dim aTasksMale(MaxAge - MinAge, Me.Factors.Length) As Task(Of Double)
      Dim aTasksFemale(MaxAge - MinAge, Me.Factors.Length) As Task(Of Double)
  
      'Cycle through all available factors
      For iParam As Integer = 0 To Me.Factors.Length - 1
          'Fetch the new factor specific parameter set
          Dim Param As FactorParameters = Me.Factors(iParam)
  
          'Get a new factor generator of the proper kind. Note that all generators are stored in their corresponding
          'FactorParameters &quot;FactorType&quot; value upon creation of the Calculation Engine to allow for easy selection
          Dim Generator As IFactor = Me.Generators(Param.FactorType).GetInstance(Me.Assumptions, Param)
  
          'Calculate the factors for both males and females and store them in the Task matrices
          For iAge As Short = MinAge To MaxAge
              'Set up a local variable and set it to the iteration value
              'Note: not doing this results in the following Warning: &quot;Using the iteration variable in a lambda expression may have unexpected results.
              'Instead, create a local variable within the loop and assign it the value of the iteration variable.&quot;
              Dim iLoopAge As Short = iAge
  
              'Run the tasks of generating the factors for both males and females
              aTasksMale(iLoopAge - MinAge, iParam + 1) = Task.Run(Function() Generator.GetFactor(0, iLoopAge))
              aTasksFemale(iLoopAge - MinAge, iParam + 1) = Task.Run(Function() Generator.GetFactor(1, iLoopAge))
          Next iAge
      Next iParam
  
      'Wait for all tasks to complete
      Task.WaitAll()
  
      'Populate the output matrices
      For iAge = MinAge To MaxAge
          For iFactor = 1 To Me.Factors.Length
              'Copy the factors to the output matrices
              Me.OutputResultsMale(iAge - MinAge, iFactor) = aTasksMale(iAge - MinAge, iFactor).Result
              Me.OutputResultsFemale(iAge - MinAge, iFactor) = aTasksFemale(iAge - MinAge, iFactor).Result
          Next iFactor
      Next iAge
  End Sub
  </code></pre>
  <p>I was hoping (and perhaps even expecting) that would do the trick and speed up the process, but instead I get a weird error I can't seem to fix, especially in the CalcCashFlow and CalcFactor routines. The CalcFactor routine is pretty short and simple:</p>
  <pre><code>    Friend Overridable Function CalcFactor() As Double
      'Set up a double representing the factor
      Dim dFactor As Double
  
      'Cycle through all cash flows
      For iPeriod As Short = 0 To Me.CashFlow.Length - 1
          'Determine the present value of the cash flow and add it to the factor value
          dFactor += Me.CashFlow(iPeriod) * Me.Assumptions.Yield.GetPV(iPeriod)
      Next iPeriod
  
      'Return the factor
      Return dFactor
  End Function
  </code></pre>
  <p>I get an IndexOutOfBounds error for the iPeriod loop variable in the CalcFactor routine. When I get the OutOfBounds error I noticed that the iPeriod variable would be (e.g.) 118 whereas the cash flow array holds only 113 values (the values for both the iPeriod variable and the length of the Factor array differ between runs / errors). I don't understand why, because the loop explicitly says iPeriod should only loop until the end of the cash flow array.
  When running the 'regular' (slow) program, iPeriod would never get above 113 in that example. But adding it to a Task somehow screws that all up. It looks like the iPeriod loop variable gets mixed up with other tasks or something, so I also tried adding a new local looping variable and setting it to the iPeriod variable, but to no avail.</p>
  <p>What am I doing wrong here?
  If you need more explanation / code, just let me know.</p>