2011-10-18 40 views
1

我正在嘗試在.Net中學習線程。使用參數方法的ThreadStart

很多的你一定已經看到了這一點:

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只接受方法名稱。那麼如何在不同的線程中調用循環方法?

+3

如果'textBox1'是一個WinForms或WPF文本框,那麼*不要這樣做*只能通過創建'TextBox'的線程來改變'.Text'屬性,這顯然不是線程你即將開始。查看「BackgroundWorker」或「Control.Invoke()」(用於WinForms)或「Dispatcher」(用於WPF)。 – dlev

回答

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

如果你需要我可以找到所以一些答案來解釋這個「問題」

+0

謝謝....它解決了我的問題。任何進一步的信息將不勝感激。 – Sandy

+0

@rapsalands這裏有*關於封閉和變量的q/a http://stackoverflow.com/q/512166/613130 – xanatos

+0

謝謝Xanatos .. – Sandy

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

非常感謝克里斯.... – Sandy

2

有一個ParameterizedThreadStart類,它使用一個參數代表可以投實例化一個線程時:

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

如果你不」 t需要對線程啓動和停止時的細粒度控制,可以將其留給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; 
} 
+0

謝謝基思.... + 1 – Sandy

0

像這樣:

new Thread(() => loop("MyString")).Start(); 

你甚至不必用的ThreadStart/ParameterizedThreadStart一塌糊塗。