
The other afternoon I ran into some nightmarish debugging with the following code:
private static void StartThreads()
{
    var values = new List<int>() { 1, 2, 3 };
    var threads = new List<Thread>();
    foreach (var value in values)
    {
        Thread t = new Thread(() => Run(value));
        threads.Add(t);
        t.Start();
    }
    // Wait for all threads to complete
    foreach (Thread t in threads)
        t.Join();
}
private static void Run(int value)
{
    Console.Write(value.ToString());
}
(I know, I know, I wish I could be using TPL but in this case I couldn't)
On my local machine, the code above ran and gave me my expected console output of 123 (your results may vary depending on what order the threads run in).
When I ran this code on my server however, the output was 333.
begin pulling out hair
Long story short, after a couple hours of investigation I figured out that the way a foreach loop works under the hood in C# ≥ 5.0, which is what I run on my local machine, works differently than a foreach loop in C# < 5.0, which is what I had on my server.
From the C# 4.0 spec, a foreach loop is really a while loop behind the scenes, meaning the code above really translates into something like this:
private static void StartThreads()
{
    var values = new List<int>() { 1, 2, 3 };
    var threads = new List<Thread>();
    IEnumerator<int> e = ((IEnumerable<int>)values).GetEnumerator();
    try
    {
        int v; // DECLARED OUTSIDE OF THE LOOP!!!
        while (e.MoveNext())
        {
            v = (int)(int)e.Current;
            Thread t = new Thread(() => Run(v));
            threads.Add(t);
            t.Start();
        }
    }
    finally
    {
        if (e != null) ((IDisposable)e).Dispose();
    }
    // Wait for all threads to complete
    foreach (Thread t in threads)
        t.Join();
}
The important thing to note in the above code is that int v gets declared outside of the while loop.
In the C# 5.0 spec, that int v gets declared inside the loop (causing it to get recreated with every iteration):
private static void StartThreads()
{
    var values = new List<int>() { 1, 2, 3 };
    var threads = new List<Thread>();
    IEnumerator<int> e = ((IEnumerable<int>)values).GetEnumerator();
    try
    {
        while (e.MoveNext())
        {
            int v; // C# 5.0 DECLARED INSIDE THE LOOP
            v = (int)(int)e.Current;
            Thread t = new Thread(() => Run(v));
            threads.Add(t);
            t.Start();
        }
    }
    finally
    {
        if (e != null) ((IDisposable)e).Dispose();
    }
    // Wait for all threads to complete
    foreach (Thread t in threads)
        t.Join();
}
Because my local machine and server were running different versions of .NET, the same exact code was producing totally different results.
Eventually I found Eric Lippert's article about the matter. Since I'm still fairly new to the world of .NET, I wasn't around for the big debate that took place in his comment's section regarding which should be the correct implementation. However, it is interesting to note that the C# devs decided to switch the logic on how the foreach loop operates so late in the game.
My eventual workaround for the .NET 3.5/C# 4.0 server was to assign the int to a newly created variable inside the foreach:
foreach (var value in values)
{
    var tempValue = value; // THE FIX
    Thread t = new Thread(() => Run(tempValue));
    threads.Add(t);
    t.Start();
}
As frustrating it may be to debug problems like this, it is nice to learn a little bit more of the language's history and idiosyncrasies.


