C#winform單執行緒事例與多執行緒事例
- 2020 年 6 月 11 日
- 筆記
- .NET, C/S winform, c#, 其他
通過例子編寫,用winform編寫的,講解單執行緒與多執行緒使用,用於非同步載入數據,介面不會卡死,數據在後台默認載入,給用戶更好的體驗。稍後會附加完整程式碼。
1、先不用執行緒,顯示一個求和,計算過程中要停留1秒後繼續計算。如果不用多執行緒頁面就會卡死,直到計算完成後才會響應。一個button按鈕,一個label
介面:
程式碼如下:
#region 不用執行緒情況 private void button1_Click(object sender, EventArgs e) { //不用執行緒點擊按鈕,窗體會卡死,10秒後恢復 int sum = 0; for (int i = 0; i < 10; i++) { sum = sum + i; label3.Text = sum.ToString(); Thread.Sleep(1000);//休息1秒 } } #endregion
2、用單執行緒進行處理,單獨開啟一個進執行緒啟動,進行每個2秒鐘進行計數顯示,並且窗體不會死。介面是一個button 兩個 label。
介面:
程式碼:
#region 多執行緒中,單獨一個執行緒運行 private void btnD_Click(object sender, EventArgs e) { //多執行緒中,單獨一個進程啟動,進行每個2秒鐘進行計數顯示,並且窗體不會死。 Thread t = new Thread(new ThreadStart(OneThreadSum));//開啟執行緒 t.IsBackground = true;//附加主執行緒,主執行緒關閉後,子執行緒也跟著關閉,簡單理解就是窗體關閉,啟動執行緒也跟著關閉。 t.Start(); } private void OneThreadSum() { try { Invoke(this, delegate { //按鈕變為灰色 防止按鈕多次點擊 //給控制項賦值就需要使用invoke this.btnD.Enabled = false; }); for (int i = 0; i < 10; i++) { Invoke(this, delegate { //通過代理賦值,通過這種方式,介面和窗口就不會卡死,窗口先展示出來,然後數據過後載入。 //給控制項賦值就需要使用invoke label2.Text = i.ToString(); }); Thread.Sleep(2000);//休息2秒 } } catch (Exception ex) { throw; } finally { //給控制項賦值就需要使用invoke Invoke(this, delegate { this.btnD.Enabled = true; }); } } /// <summary> /// 在執行緒中通過代理給控制項賦值 /// </summary> /// <param name="col"></param> /// <param name="method"></param> public void Invoke(Control col, MethodInvoker method) { if (!col.IsHandleCreated) return;//當前控制項是否被創建 if (col.IsDisposed) return;//當前控制項是否被銷毀 if (col.InvokeRequired) col.Invoke(method);//是否允許被請求 else method(); } #endregion
3、模擬餐館來人吃飯,客人來了點菜是一個執行緒,客人就餐時一個執行緒,客人結賬時一個執行緒,一共3個執行緒,各自處理各自的事情,一個客人名稱textbox, 一個客人來了button,一個啟動初始化按鈕,listbox1 代表點餐記錄 ,listbox2 代表就餐記錄 ,listbox3代表結賬記錄 。
介面:
程式碼:
#region 用多執行緒 不是單獨一個執行緒,以3個執行緒為例 //模擬餐館來人吃飯,客人來了點菜是一個執行緒,客人吃飯時一個執行緒,客人結賬時一個執行緒,一共3個執行緒 private void 啟動監聽執行緒_Click(object sender, EventArgs e) { 啟動監聽執行緒.Enabled = false;//初始化只允許一次,否則會開啟很多執行緒,所以要灰色 wait1 = new ManualResetEvent(false);//啟動訊號,等待著。 t1 = new Thread(new ThreadStart(F1)) { IsBackground = true }; t1.Start();//初始化執行緒t1 點餐執行緒 wait2 = new ManualResetEvent(false); t2 = new Thread(new ThreadStart(F2)) { IsBackground = true }; t2.Start();//初始化執行緒t2 用餐執行緒 wait3 = new ManualResetEvent(false); t3 = new Thread(new ThreadStart(F3)) { IsBackground = true }; t3.Start();//初始化執行緒t3 結賬執行緒 } private void 客人來了_Click(object sender, EventArgs e) { data1.Add(textBox1.Text);//這個時候客人來了,增加到list中。 wait1.Set();//告訴服務員,客人來了,要開始點餐了。 } private IList data1 = new ArrayList();//存儲來客人 private Thread t1 = null;//點菜執行緒 private ManualResetEvent wait1 = null;//訊號,相當於服務員,客人來了需要告訴 private void F1() { while (true) { //2秒鐘查詢一次。 if (wait1.WaitOne(2000, false)) { if (data1 == null || data1.Count == 0) { //如果一個人都沒有的話,不需要點菜 Invoke(this, delegate { listBox1.Items.Add("無客人!"); }); wait1.Reset();//執行緒停止,繼續等待。 continue;//結束本次循環 } //程式執行到這裡說明有人,客人開始點餐。 string r = data1[0] as string; Invoke(this, delegate { listBox1.Items.Add(r + "->開始點餐!"); }); Thread.Sleep(2000); data2.Add(r);//增加到用餐list中 wait2.Set();//告訴可以開始用餐了。 data1.RemoveAt(0);//客人從隊列中移除 } } } private IList data2 = new ArrayList();//存儲用餐人 private Thread t2 = null;//用餐執行緒 private ManualResetEvent wait2 = null;//訊號,用餐訊號 private void F2() { while (true) { if (wait2.WaitOne(2000, false)) { if (data2 == null || data2.Count == 0) { Invoke(this, delegate { listBox2.Items.Add("無用餐人!"); }); wait2.Reset(); continue; } //程式執行到這裡說明有人,客人開始用餐。 string r = data2[0] as string; Invoke(this, delegate { listBox2.Items.Add(r + "->用餐中...!"); }); Thread.Sleep(3000); data3.Add(r);//增加到結賬的list中 wait3.Set();//告訴客人可以開始結賬了 data2.RemoveAt(0);//客人從隊列中移除 } } } private IList data3 = new ArrayList();//存儲結賬人 private Thread t3 = null;//結賬執行緒 private ManualResetEvent wait3 = null;//結賬訊號 private void F3() { while (true) { if (wait3.WaitOne(2000, false)) { if (data3 == null || data3.Count == 0) { Invoke(this, delegate { listBox3.Items.Add("無結賬人!"); }); wait3.Reset(); continue; } //程式執行到這裡說明有人,客人開始結賬。 string r = data3[0] as string; Invoke(this, delegate { listBox3.Items.Add(r + "->結賬買單!"); }); Thread.Sleep(4000); data3.RemoveAt(0);//客人從隊列中移除 } } } /// <summary> /// 在執行緒中通過代理給控制項賦值 /// </summary> /// <param name="col"></param> /// <param name="method"></param> public void Invoke(Control col, MethodInvoker method) { if (!col.IsHandleCreated) return;//當前控制項是否被創建 if (col.IsDisposed) return;//當前控制項是否被銷毀 if (col.InvokeRequired) col.Invoke(method);//是否允許被請求 else method(); } #endregion
csdn 源碼下載鏈接://download.csdn.net/download/njxiaogui/12514492