这是我的代码。在 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;
}
}
}
答案 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();
}