初始化线程时出错(Closure?)

时间:2012-06-29 19:32:25

标签: c# multithreading closures

这是我在这个论坛的第一个问题,所以我希望明确:

我在C#中使用Visual Studio 2010 RTM编程

该类的构造函数(转换为线程)始终从最后一个Dictionary Entry中获取值。 我不知道我做错了什么,有人吗?

本准则不起作用:

    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();
        }
    }

相反,此代码完美无缺:

    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();
        }
    }

2 个答案:

答案 0 :(得分:2)

这是一个非常常见的错误,称为“捕获循环变量”或“关闭变量”。

 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)); 
 }

您使用相同的变量pair开始了许多线程。此“捕获”变量的行为类似于引用传递参数。当线程开始执行时foreach()完成,它们都使用最后一个元素。

另外,您可能不应该使用裸线程。使用TPL中的ThreadPool或Task对象。

答案 1 :(得分:1)

是。你是被称为“捕获变量”的受害者。这里捕获的是pair。请参阅此文章:http://blog.sluu.org/captured-variable/

修改:我还注意到OP的第一个代码段中出现语法错误:colas = new Dictionary<string, Queue<string>>();此行中有一个更大的符号。