线程携带重复的字符串对象

时间:2013-10-15 20:41:50

标签: c# .net multithreading

这是我的代码。在 startLog 方法中创建的日志文件具有从1到1000的正确计数,但由 log 方法创建的日志文件具有重复值。例如,如果重复88,则错过89,下一个打印的数字是90.任何人都可以解释为什么会发生这种情况?

          namespace TestThreading
            {
                public partial class Form1 : Form
                {
                    NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
                    public Form1()
                    {
                        InitializeComponent();
                    }

                    private void Form1_Load(object sender, EventArgs e)
                    {
                    }

                    private void button1_Click(object sender, EventArgs e)
                    {
                        new Thread(startLog).Start();
                    }
                    private void startLog()
                    {
                        int i = 0;
                        string str;
                        while (i < 1000)
                        {
                            str = (++i).ToString();
                            logger.Trace(str);
                            Thread t = new Thread(() => log(new TestObject(str)));
                            t.Start();
                        }
                        MessageBox.Show("Done");
                    }
                    private void log(TestObject obj)
                    {
                        logger.Debug(obj.getCount());
                    }
                }

                public class TestObject
                {
                    string count;
                    public TestObject(string i)
                    {
                        count = i;
                    }
                    public string getCount()
                    {
                        return count;
                    }
                }
            }

2 个答案:

答案 0 :(得分:2)

在创建新线程时关闭变量(str),然后在代码运行之前改变同一个变量。

请记住,关闭变量的闭包不会超过*值。当您的匿名方法确定传递给log的内容时,str已被更改为另一个值。

解决方案很简单。只需在循环内部中定义str ,这样每个闭包都有自己的变量来关闭:

while (i < 1000)
{
    string str = (++i).ToString();
    logger.Trace(str);
    Thread t = new Thread(() => log(new TestObject(str)));
    t.Start();
}

现在变量在关闭后永远不会改变;而是为每个闭包创建一个新的str变量,每个变量都有自己的变量。

答案 1 :(得分:0)

正如Servy已经回答的那样,这是因为str变量是在闭包之外定义的

如果需要,您还可以使用ParameterizedThreadStart并传递循环内修改的变量。这实际上有效

    static void Main(string[] args)
    {
        int i = 0;
        string str;
        while (i < 1000)
        {
            str = (++i).ToString();
            Thread t = new Thread((s) => Console.WriteLine(s));
            t.Start(str);
        }

        Console.ReadLine();
    }