(一)使用線程的理由
1、可以使用線程將代碼同其他代碼隔離,提高應用程序的可靠性。
2、可以使用線程來簡化編碼。
3、可以使用線程來實現並發執行。
(二)基本知識
1、進程與線程:進程作為操作系統執行程序的基本單位,擁有應用程序的資源,進程包含線程,進程的資源被線程共享,線程不擁有資源。
2、前台線程和后台線程:通過Thread類新建線程默認為前台線程。當所有前台線程關閉時,所有的后台線程也會被直接終止,不會拋出異常。
3、掛起(Suspend)和喚醒(Resume):由於線程的執行順序和程序的執行情況不可預知,所以使用掛起和喚醒容易發生死鎖的情況,在實際應用中應該盡量少用。
4、阻塞線程:Join,阻塞調用線程,直到該線程終止。
5、終止線程:Abort:拋出 ThreadAbortException 異常讓線程終止,終止后的線程不可喚醒。Interrupt:拋出 ThreadInterruptException 異常讓線程終止,通過捕獲異常可以繼續執行。
6、線程優先級:AboveNormal BelowNormal Highest Lowest Normal,默認為Normal。
(三) 線程生命周期
- 未啟動狀態:當線程實例被創建但 Start 方法未被調用時的狀況。
- 就緒狀態:當線程准備好運行並等待 CPU 周期時的狀況。
- 不可運行狀態:死亡狀態:當線程已完成執行或已中止時的狀況。
- 已經調用 Sleep 方法
- 已經調用 Wait 方法
- 通過 I/O 操作阻塞
(四) Thread 常用方法:
- public void Interrupt() 中斷處於 WaitSleepJoin 線程狀態的線程。
- public void Join() 在繼續執行標准的 COM 和 SendMessage 消息泵處理期間,阻塞調用線程,直到某個線程終止為止。
- public void Start() 開始一個線程
- public static void Sleep(int millisecondsTimeout) 讓線程暫停一段時間
一 普通線程
分為兩種,一種是不需要給子線程傳參數,Thread t = new Thread(new ThreadStart(void () target)); 另一種是要給子線程傳一個參數,Thread t = new Thread(new ParameterizedThreadStart(void (object) target));

// 普通線程 private void btn1_Click(object sender, EventArgs e) { progressBar.Value = 0; Thread tt = new Thread(new ThreadStart(DoWork1)); tt.Name = "不帶參數普通線程"; tt.Start(); Thread t = new Thread(new ParameterizedThreadStart(DoWork2)); t.Name = "帶參數普通線程"; t.IsBackground = true; t.Start(100); _msg += "當前線程的執行狀態:" + t.IsAlive + "\r\n"; _msg += "當前托管線程的唯一標識:" + t.ManagedThreadId + "\r\n"; _msg += "線程名稱:" + t.Name + "\r\n"; _msg += "當前線程的狀態:" + t.ThreadState; MessageBox.Show("消息:\r\n" + _msg, "提示", MessageBoxButtons.OK); } // 線程方法 private void DoWork1() { for (int i = 0; i < 100; i++) { // 跨線程訪問 UI,BeginInvoke 采用異步委托 progressBar.BeginInvoke(new EventHandler((sender, e) => { progressBar.Value = i; }), null); } } // 線程方法 private void DoWork2(object obj) { for (int i = 0; i < (int)obj; i++) { progressBar.BeginInvoke(new EventHandler((sender, e) => { progressBar.Value = i; }), null); } }
二 線程池
public static bool QueueUserWorkItem(WaitCallback);
public static bool QueueUserWorkItem(WaitCallback, object);
線程池默認為后台線程(IsBackground)

private void btn3_Click(object sender, EventArgs e) { ThreadPool.QueueUserWorkItem(DoWork2, 100); // 或者 ThreadPool.QueueUserWorkItem((s) => { int minWorkerThreads, minCompletionPortThreads, maxWorkerThreads, maxCompletionPortThreads; ThreadPool.GetMinThreads(out minWorkerThreads, out minCompletionPortThreads); ThreadPool.GetMaxThreads(out maxWorkerThreads, out maxCompletionPortThreads); MessageBox.Show(String.Format("WorkerThreads = {0} ~ {1}, CompletionPortThreads = {2} ~ {3}", minWorkerThreads, maxWorkerThreads, minCompletionPortThreads, maxCompletionPortThreads)); DoWork2(100); }); } // 線程方法 private void DoWork2(object obj) { for (int i = 0; i < (int)obj; i++) { // Thread.Sleep(50); progressBar.BeginInvoke(new EventHandler((sender, e) => { progressBar.Value = i; }), null); } }
三 BackgroundWorker

private void btn4_Click(object sender, EventArgs e) { progressBar.Value = 0; BackgroundWorker bw = new BackgroundWorker(); bw.WorkerReportsProgress = true;// 是否報告進度更新 // 線程執行 bw.DoWork += new DoWorkEventHandler((obj, args) => { for (int i = 0; i < 100; i++) { bw.ReportProgress(i); } }); // UI主線程顯示進度 bw.ProgressChanged += (obj, progressChangedEventArgs) => { progressBar.Value = progressChangedEventArgs.ProgressPercentage; }; // 線程執行完成后的回調函數 bw.RunWorkerCompleted += (obj, runWorkerCompletedEventArgs) => { MessageBox.Show("子線程執行完成!"); }; if (!bw.IsBusy) { bw.RunWorkerAsync(); } }
三 Task(.NET 4.0以上版本)

private void btn5_Click(object sender, EventArgs e) { progressBar.Value = 0; Task<bool> t = new Task<bool>(maxValue => DoWork((int)maxValue), progressBar.Maximum); t.Start(); t.Wait(); // 任務完成后繼續延續任務 Task cwt = t.ContinueWith(task => MessageBox.Show("The result is " + t.Result)); } // 線程方法 private bool DoWork(int maxValue) { for (int n = 0; n < maxValue; n++) { progressBar.BeginInvoke(new EventHandler((sender, e) => { progressBar.Value = n; }), null); } return true; }
四 異步委托

public delegate string MyDelegate(object arg); private void btn6_Click(object sender, EventArgs e) { MyDelegate myDelegate = new MyDelegate(DoWork3); IAsyncResult result = myDelegate.BeginInvoke(100, DoWork2Callback, "回調函數參數"); // 異步執行完成 string resultStr = myDelegate.EndInvoke(result); } // 線程函數 private string DoWork3(object arg) { for (int n = 0; n < (int)arg; n++) { progressBar.BeginInvoke(new EventHandler((sender, e) => { progressBar.Value = n; }), null); } return "Finished"; } // 異步回調函數 private void DoWork2Callback(IAsyncResult arg) { MessageBox.Show(arg.AsyncState.ToString()); }
五 附 跨線程訪問UI之 SynchronizationContext (同步上下文)

private void btn2_Click(object sender, EventArgs e) { SynchronizationContext context = SynchronizationContext.Current; new Thread(() => { for (int i = 0; i < 100; i++) { // Send方法是發送一個異步請求消息 //context.Send((s) => //{ // progressBar.Value = i; //}, null); // Post方法是發送一個同步請求消息 context.Post((s) => { progressBar.Value = i; }, null); } }).Start(); }
六 Task+事件+控制(暫停、繼續):
using System; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace TaskTest { public partial class Form1 : Form { public event EventHandler<MyEventArgs> MyNotify; private delegate void DelegateSetProgress(MyEventArgs e); CancellationTokenSource tokenSource; CancellationToken token; ManualResetEvent reset; public Form1() { InitializeComponent(); MyNotify += new EventHandler<MyEventArgs>(GetProgress); } private void SetProgress(MyEventArgs e) { if(progressBar1.InvokeRequired) { Invoke(new DelegateSetProgress(SetProgress), e); } else { progressBar1.Value = e.value; txtMessage.AppendText(e.text); } } private void btnStart_Click(object sender, EventArgs e) { tokenSource = new CancellationTokenSource(); token = tokenSource.Token; reset = new ManualResetEvent(true); // 初始化為true時執行WaitOne不阻塞 MyNotify(null, new MyEventArgs() { value = 0, text = $"程序已經啟動\n" }); Task.Run(() => { for (int i = 1; i <= 100; i++) { if (token.IsCancellationRequested) return; reset.WaitOne(); MyNotify(null, new MyEventArgs() { value = i, text = $"進度為:{i}/100 \n" }); Thread.Sleep(100); } },token); } private void GetProgress(object sender,EventArgs e) { SetProgress(e as MyEventArgs); } private void btnPause_Click(object sender, EventArgs e) { btnPause.Text = btnPause.Text == "暫停" ? "繼續" : "暫停"; if (btnPause.Text == "暫停") reset.Set(); else reset.Reset(); } private void btnStop_Click(object sender, EventArgs e) { tokenSource.Cancel(); } } public class MyEventArgs : EventArgs { public int value = 0; public string text = string.Empty; } }
七 參考資料:
☆參考博客 http://www.cnblogs.com/luxiaoxun/p/3280146.html
☆多線程講解 http://www.w3cschool.cc/csharp/csharp-multithreading.html