1.如果只是啟動一個新線程,不需要傳入參數,不需要線程返回結果,可以直接使用ThreadStart(),
Thread類接收一個ThreadStart委托或ParameterizedThreadStart委托的構造函數。ThreadStart委托中 作為參數的方法 不需要參數,並且沒有返回值。ParameterizedThreadStart委托,可以在線程start的時候,傳入參數,利用這個參數可以向線程傳遞參數(ParameterizedThreadStart是一個有參的、返回值為void的委托,參數類型必須是object)。
private void btOnlineLogin_Click(object sender, EventArgs e) { Thread CheckStatusThread = new Thread(new ThreadStart(CheckStatus));
CheckStatusThread.Start(); //無參和返回值的多線程
}
private void CheckStatus()
{
//do some thing here
}
2. 如果需要向線程傳入參數,但不需要線程返回值,用ParameterizedThreadStart是一個有參的、返回值為void的委托,參數類型必須是object,且只能有一個object參數傳入,
如果要傳入多個參數,可以用下面3中的Func()或者定義一個結構體,結構體包含你要傳入的參數,然后把結構體當作object傳入。
private void btOnlineLogin_Click(object sender, EventArgs e) { Thread CheckStatusThread = new Thread(new ParameterizedThreadStart(CheckStatus));
CheckStatusThread.Start("print me"); //有傳入參,無返回值的多線程
}
private void CheckStatus(object value)
{
Console.WriteLine(value)
}
//==============================總之上述用Thread方式,都沒有返回值。
3.如果新線程不需要傳入參數,但是需要得到返回結果,可以有兩種做法:
a: 定義一個全局變量,按照上述1中方法啟動一個無參無函數返回值的線程,將要返回的結果設置給全局變量
public class Class1
{
bool Ready= false;
private void btOnlineLogin_Click(object sender, EventArgs e)
{
Thread CheckStatusThread = new Thread(new ThreadStart(CheckStatus));
CheckStatusThread.Start(); //無參和返回值的多線程
while(!Ready)
{
Console.WriteLine("wait for status to ready");
}
}
private void CheckStationLockedWindow()
{
System.Threading.Thread.Sleep(1000); //使 UI 線程有了處理界面消息的機會
Ready = true;
}
}
b.使用Func(in_param_type, in_param_type, out_param_type), 然后使用Func的BeginInvoke() 異步啟動一個新線程,該做法界面會卡住。
private void button33_Click(object sender, EventArgs e)
{
Func<bool> test = MyTestMethod;
// Func<bool> test = new Func<bool>(MyTestMethod); //這樣一樣
IAsyncResult result = test.BeginInvoke(null, null); //不用傳入參數
bool fin = test.EndInvoke(result);
if(fin)
{
Console.WriteLine("OK.........");
}
}
private bool WaitAndCreateEmptyFwFolder()
{
Stopwatch timer = new Stopwatch();
timer.Reset();
timer.Start();
while(timer.ElapsedMilliseconds <20*1000)
{
System.Threading.Thread.Sleep(1000); //使 UI 線程有處理界面消息的機會,防止卡住
Application.DoEvents();
Console.WriteLine("Elappsed time:" + timer.ElapsedMilliseconds.ToString());
}
return true;
}
3. 如果即需要給線程傳入參數還需要得到線程返回值,還是可以用Func(), 用Func() 可以不用定義自己的delegate了。
public class Class1
{
private void button33_Click(object sender, EventArgs e)
{
Func<string, bool> test = PrintSomeThing;
IAsyncResult result = test.BeginInvoke("Print me", null, null);
bool fin = test.EndInvoke(result);
if (fin)
{
Console.WriteLine("OK.........");
}
}
private bool PrintSomeThing(string arg)
{
Stopwatch timer = new Stopwatch();
timer.Reset();
timer.Start();
while (timer.ElapsedMilliseconds < 10 * 1000)
{
System.Threading.Thread.Sleep(1000); //使 UI 線程有處理界面消息的機會
Application.DoEvents();
Console.WriteLine(arg);
}
return true;
}
}
4. 第四種多線程用task:System.Thread.Tasks.Task
Task的參數有兩種,一種是Action(無返回值),一種是Func。
public class Class1
{
private void button33_Click(object sender, EventArgs e)
{
//==============帶有返回值和傳入參數的
//Task task = Task<bool>.Factory.StartNew(new Func<object,bool>(TaskMthod),"321"); //帶有返回值和傳入參數的
Task<bool> task = new Task<bool>(TaskMthodWithReturnAndInParam, "123"); //new Task<>()中的<>里面放返回值類型,
//()里面放Func類型method名字。
// 如果直接用new Task()沒有<>則沒有返回值,里面放Action類型method名字。
task.Start();//start async
//Console.WriteLine(task.Result.ToString()); //task.Result will block the thread unitil the task is done and run to next step, UI will stuck
//task.Wait(); //will block until done
while(!task.IsCompleted) // this won't block UI
{
Application.DoEvents();
}
Console.WriteLine(task.Result.ToString());
//================只有返回值,無傳入參數的
Task<bool> task2 = new Task<bool>(TaskMthodWithReturnNoInParam);
task2.Start();//start async
while(!task2.IsCompleted)
{
Application.DoEvents();
}
Console.WriteLine(task2.Result.ToString());
//Task.WaitAll(task1,task2); //wait all task done
//===================沒有返回值,只有傳入參數的
Task task = Task.Run(() => TaskMthodWithInParamOnly(true, true));
while (!task.IsCompleted)
{
Application.DoEvents();
}
}
private void TaskMthodWithInParamOnly(bool val1, bool val2)
{
Stopwatch timer = new Stopwatch();
timer.Reset();
timer.Start();
while (timer.ElapsedMilliseconds < 20 * 1000)
{
Console.WriteLine("Elappsed time:" + timer.ElapsedMilliseconds.ToString());
}
}
private bool TaskMthodWithReturnNoInParam() { Stopwatch timer = new Stopwatch(); timer.Reset(); timer.Start(); while (timer.ElapsedMilliseconds < 20 * 1000) { Console.WriteLine("Elappsed time:" + timer.ElapsedMilliseconds.ToString()); } return true; } private bool TaskMthodWithReturnAndInParam(object val) { Stopwatch timer = new Stopwatch(); timer.Reset(); timer.Start(); while (timer.ElapsedMilliseconds < 20 * 1000) { Console.WriteLine(val.ToString()); } return true; }
}
如下內容引自https://www.cnblogs.com/liuqiyun/p/8110058.html:
BeginInvoke 方法所調用的委托無論如何都是在 UI 線程中執行的。
那 BeginInvoke 究竟有什么用呢?
在多線程編程中,我們經常要在工作線程中去更新界面顯示,而在多線程中直接調用界面控件的方法是錯誤的做法,具體的原因可以在看完我的這篇之后看看這篇:在多線程中如何調用Winform,如果你是大牛的話就不要看我這篇了,直接看那篇吧,反正那篇文章我沒怎么看懂。
Invoke 和 BeginInvoke 就是為了解決這個問題而出現的,使你在多線程中安全的更新界面顯示。
正確的做法是將工作線程中涉及更新界面的代碼封裝為一個方法,通過 Invoke 或者 BeginInvoke 去調用,兩者的區別就是一個導致工作線程等待,而另外一個則不會。
而所謂的“一面響應操作,一面添加節點”永遠只能是相對的,使 UI 線程的負擔不至於太大而以,因為界面的正確更新始終要通過 UI 線程去做,我們要做的事情是在工作線程中包攬大部分的運算,而將對純粹的界面更新放到 UI 線程中去做,這樣也就達到了減輕 UI 線程負擔的目的了。