1

This is my first question in this forum, so i hope to be clear:

I´m using Visual Studio 2010 RTM Programming in C#

The constructor of the class, which is converted to a thread, are always taking the values from the last Dictionary Entry. I don´t know what i´m doing wrong, someone?

This Code doesn´t work:

    Dictionary<string, Queue<string>> colas;

    public DataDispatcher(Dictionary<string, int> lectoras, ReadEventHandler callback)
    {
        colas = new Dictionary<string, Queue<string>>();

        foreach (KeyValuePair<string, int> pair in lectoras)
        {
            colas.Add(pair.Key, new Queue<string>>());

            Thread hilo = new Thread(
                () => new ReadHandler(pair.Value, colas[pair.Key], callback));

            hilo.Name = "Hilo-" + hilo.ManagedThreadId.ToString();

            hilo.Start();
        }
    }

Instead, this Code works perfectly:

    Dictionary<string, Queue<string>> colas;

    public DataDispatcher(Dictionary<string, int> lectoras, ReadEventHandler callback)
    {
        colas = new Dictionary<string, Queue<string>>();

        foreach (KeyValuePair<string, int> pair in lectoras)
        {
            Queue<string> qs = new Queue<string>();

            colas.Add(pair.Key, qs);

            int jaula = pair.Value;

            Thread hilo = new Thread(
                () => new ReadHandler(jaula, qs, callback));

            hilo.Name = "Hilo-" + hilo.ManagedThreadId.ToString();

            hilo.Start();
        }
    }
4

2 回答 2

2

It is a very common error called 'capturing the loop variable', or 'closing over the variable'.

 foreach (KeyValuePair<string, int> pair in lectoras)
 {
     colas.Add(pair.Key, new Queue<string>>());  // here 'pair' is OK

     var copy = pair;  // this is the fix, make a new 'copy' for each thread

     Thread hilo = new Thread(
         () => new ReadHandler(copy.Value, colas[copy.Key], callback)); 
 }

You were starting a number of threads all using the same variable pair. This 'captured' variable behaves like a pass-by-reference parameter. By the time the Threads start executing the foreach() is done and they all use the last element.

On a side note, you probably shouldn't be using bare Threads for this. Use the ThreadPool or Task objects from the TPL.

于 2012-06-29T19:40:41.147 回答
1

Yes. You are a victim of what's called "Captured Variable." The thing being captured here is pair. See this article: http://blog.sluu.org/captured-variable/

Edit: I also notice a syntax error in OP's first snippet: colas = new Dictionary<string, Queue<string>>(); There's an extra greater sign in this line.

于 2012-06-29T19:44:06.987 回答