views:

44

answers:

2

I'm trying to understand why this code is not working.

    private static object _lock;

    public static void Main (string[] args)
    {
        Thread thread;
        _lock = new object();

        foreach (int num in Enumerable.Range(0,5)) {
            thread  = new Thread (() => print(num.ToString()));
            thread.Start(); 
        }
    }

    public static void print(string text)
    {
        lock(_lock)
        {
            Console.WriteLine(text);
        }
    }

I end up with an output of

4 1 4 4 3

or any other random number of digits. Why does it repeat digits?

+3  A: 

Because each thread is refering to the loop variable, and does not get its own copy at the time you create the thread.

Notice that the compiler is warning you: "Access to a modified closure".

    foreach (int num in Enumerable.Range(0,5))
    {
        int loopnum = num;

        thread = new Thread(() => print(loopnum.ToString())); 
        thread.Start();  
    }
Mitch Wheat
oh my god of course. Thank you very much. I can't believe I didn't realize that.
Leon
Clarification for poster: This is a little "gotcha" with for-each and closures in C# (the variable introduced in the for-each is the *same* variable each loop): This will "fix it": `foreach (int _num in ...) { int num = _num; /* same */ }`
pst
A: 

Your lock does not do anything at all; only one thread is locking on that object - the one that is starting the others. Those other threads never contest for that lock at all.

Andrew Barber
Thanks, I've updated the code.
Leon
Yes, but what's the cause? ;-)
pst