我正在尝试在.Net中学习线程。
你们中的许多人一定见过这个:
private void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(loop));
t.Start();
}
private void loop()
{
for (int i = 0; i < 100000; i++)
{
textBox1.Text = i.ToString();
}
}
它工作正常,但是如果我的循环方法中有参数,例如:
private void loop(string str)
{
for (int i = 0; i < 100000; i++)
{
textBox1.Text = i + str;
}
}
然后如何在ThreadStart中调用此方法,因为ThreadStart只接受方法名称。那么如何在不同的线程中调用循环方法呢?
答案 0 :(得分:2)
您使用的是ParameterizedThreadStart:http://msdn.microsoft.com/en-us/library/system.threading.parameterizedthreadstart.aspx
Thread t = new Thread(new ParameterizedThreadStart(loop));
t.Start("Foo");
// Note the use of Object here to match the delegate signature
private void loop(Object state)
{
var str = state as String;
for (int i = 0; i < 100000; i++)
{
// For what it is worth, this is illegal:
// textBox1.Text = i + str;
// You need to Invoke back to the UI thread to access a control's properties:
textBox1.Invoke(()=> { textBox1.Text = i + str; });
}
}
答案 1 :(得分:2)
有一个ParameterizedThreadStart类,当实例化一个线程时,可以强制转换具有单个参数的Delegates:
private void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ParameterizedThreadStart(loop));
t.Start(str);
}
private void loop(string str)
{
for (int i = 0; i < 100000; i++)
{
//the code you had is a no-no when you are multithreading;
//all UI updates must occur on the main thread
//textBox1.Text = i + str;
UpdateTextBoxText(textBox1, i+str);
}
}
private void UpdateTextBoxText(TextBox textBox, string text)
{
//the method will invoke itself on the main thread if it isn't already running there
if(InvokeRequired)
{
this.Invoke((MethodInvoker)(()=>UpdateTextBoxText(TextBox textBox, string text)));
return;
}
textBox.Text = text;
}
如果你不需要对线程的启动和停止时间进行非常细粒度的控制,你可以将它留给ThreadPool并使用Delegate.BeginInvoke:
private void button1_Click(object sender, EventArgs e)
{
Action<string> method = loop;
method.BeginInvoke(str, null, null);
}
private void loop(string str)
{
for (int i = 0; i < 100000; i++)
{
//textBox1.Text = i + str;
UpdateTextBoxText(textBox1, i+str);
}
}
private void UpdateTextBoxText(TextBox textBox, string text)
{
//the method will invoke itself on the main thread if it isn't already running there
if(InvokeRequired)
{
this.Invoke((MethodInvoker)(()=>UpdateTextBoxText(textBox, text)));
return;
}
textBox.Text = text;
}
答案 2 :(得分:2)
Thread t = new Thread(new ParameterizedThreadStart(loop));
t.Start("Hello world");
private void loop(object obj)
{
string str = (string)obj;
for (int i = 0; i < 100000; i++)
{
// Don't do this: you can't change a control from another thread. Danger Will Robinson!
textBox1.Text = i + str;
}
}
请注意,loop
方法必须接受object
参数,因此您必须将object
转换为您的类型。如果您不想要,可以使用闭包和匿名方法:
string str = "Hello world";
Thread t = new Thread(() => {
for (int i = 0; i < 100000; i++)
{
// Don't do this: you can't change a control from another thread. Danger Will Robinson!
textBox1.Text = i + str;
}
});
t.Start();
通过这种方式,匿名方法将在str
周围“关闭”,并且它将类似,就像您传递了参数一样。 类似因为关闭变量存在差异/问题。实际上我会写类似的东西:
string str = "Hello world";
{
string str2 = str;
Thread t = new Thread(() => {
for (int i = 0; i < 100000; i++)
{
// Don't do this: you can't change a control from another thread. Danger Will Robinson!
textBox1.Text = i + str2;
}
});
t.Start();
}
这样其他任何人都无法“触摸”str2
。
如果您需要,我可以在SO上找到解释这个“问题”的答案
答案 3 :(得分:1)
看看ParameterizedThreadStart,它允许您将参数传递给线程启动函数。
答案 4 :(得分:0)
像这样:
new Thread(() => loop("MyString")).Start();
你甚至不必乱用ThreadStart / ParameterizedThreadStart。