2

Why does this not every complete? Instead it throws an exception, like the exception wasn't caught. Moreover, the exceptions "Index out of bounds of array" doesn't make sense to me.

        int n = 3;
        string[] names = new string[] { "sally", "fred", "gina" };
        Task[] myTasks = new Task[n];
        for (int y = 0; y < n; y++)
        {
            myTasks[y] = Task.Factory.StartNew(() =>
            {
                Action<string> action = (name) =>
                {
                    try
                    {
                        throw new Exception(name + ", I bet you can't catch me.");
                    }
                    catch (Exception e)
                    {
                        //I caught you... didn't I?
                    }
                };
                action(names[y]);
            });
        }

        Task.WaitAll(myTasks);
        Console.WriteLine("All tasks complete.");//This line is never reached;
RexCardan
  • 398
  • 2
  • 7
  • You should tag this with the language in which the code is written. I'm guessing C# due to the capital letters in the methods and the `=>` lambda notation. – nrubin29 Aug 16 '14 at 18:35

2 Answers2

8

The lambda function you have inside the StartNew parentheses is forming a closure which is "capturing" the outer variable "y"...it doesn't access the value that it was...during the loop iteration...rather, when the captured variable is accessed in that lambda function...that's when it tries to get the value.

Your "y" variable eventually gets to the value "3" (via the loop y++)....because that causes the "loop for the creation of your "Actions")....to exit (i.e. 3 is not less than 3).

But when any of the Tasks that you created is executing the line action(names[y]) it is accessing the closed variable "y"...which "may" have already reached "3"...and the "3" is not a valid index in your array....it all depends on how quickly or slowly those tasks were scheduled as to whether you hit the problem or not...a classic race condition.

Colin Smith
  • 12,375
  • 4
  • 39
  • 47
  • Thanks, that makes sense. I didn't think of the variable ever reaching 3 but I guess it technically does before the loop stops. Very interesting. I can now sleep in peace. – RexCardan Aug 17 '14 at 04:44
1

I did figure out that by setting a variable outside of the task for name

var name = names[y];

and using this instead of accessing the array from within the task, it works. I still don't understand why.

RexCardan
  • 398
  • 2
  • 7
  • 1
    The reason is [variable closure](http://stackoverflow.com/questions/271440/captured-variable-in-a-loop-in-c-sharp) of in the lambada you created. If you did `var z = y;` inside the for loop but before the `Task` then used `names[z]` inside the task it would work fine. – Scott Chamberlain Aug 16 '14 at 18:59