網上找的,做個筆記記錄一下。
有這么一個需求,就是巡檢多台服務器是否都在線,點擊巡檢按鈕后,按行讀取DataGridView中的數據,並啟行線程執行,這時會存在多個線程同時運行,但是什么時候給出用戶提醒,說都巡檢完成了呢,需要用到一個線程狀態的檢測。
最后的效果是這樣子的,多個線程對表格按行進行服務器的巡檢,只有等所有的巡檢線都結束后,等待線程才會彈出一個巡檢完畢的提示框,在巡檢的過程中,不會卡主界面。
1、新建一個類,用於處理線程狀態的計數,用於解決EventWaitHandle時線程不能超過64個的問題
public class MutipleThreadResetEvent : IDisposable { private readonly ManualResetEvent done; private readonly int total; private long current; /// <summary> /// 構造函數 /// </summary> /// <param name="total">需要等待執行的線程總數</param> public MutipleThreadResetEvent(int total) { this.total = total; current = total; done = new ManualResetEvent(false); } /// <summary> /// 喚醒一個等待的線程 /// </summary> public void SetOne() { // Interlocked 原子操作類 ,此處將計數器減1 if (Interlocked.Decrement(ref current) == 0) { //當所以等待線程執行完畢時,喚醒等待的線程 done.Set(); } } /// <summary> /// 等待所以線程執行完畢 /// </summary> public void WaitAll() { done.WaitOne(); } /// <summary> /// 釋放對象占用的空間 /// </summary> public void Dispose() { ((IDisposable)done).Dispose(); } }
2、定義一個結構體,用於存放線程需要的參數和MutipleThreadResetEvent
struct webInfo { public int xh; public string lx; public string path; public object mre; //public ManualResetEvent mre; }
3、在DataGridView中使用
int num = DG_show.RowCount - 1; for (int i = 0; i < DG_show.RowCount - 1; i++) { DG_show.Rows[i].Cells["驗證結果"].Value = ""; DG_show.Rows[i].DefaultCellStyle.BackColor = Color.White; } //開始進行驗證 //manualEvents.Clear(); //以前的代碼,可以刪除 PR1.Maximum = num; PR1.Minimum = 0; var countdown = new MutipleThreadResetEvent(num); webInfo info1; ThreadPool.SetMaxThreads(5,5); //設置最大的線程數量 for (int i = 0; i < DG_show.RowCount - 1; i++) { //ManualResetEvent mre = new ManualResetEvent(false); //manualEvents.Add(mre); info1.xh = i; //info1.mre = mre; info1.mre = countdown; info1.lx = DG_show.Rows[i].Cells["方式"].Value.ToString().Trim(); info1.path = DG_show.Rows[i].Cells["地址"].Value.ToString().Trim(); //Thread thread1 = new Thread(new ParameterizedThreadStart(CheckResult)); //thread1.Start(info1);
//進行巡檢的線程 ThreadPool.QueueUserWorkItem(CheckResult, info1); } //等待所有巡檢線程執行完畢的線程 Thread th1 = new Thread(new ParameterizedThreadStart(WaitThreadEnd)); th1.Start(countdown);
CheckResult和WaitThreadEnd就是具體的業務處理
4、巡檢線程和等待線程中的寫法
巡檢線程
private void CheckResult(object info) { webInfo web = (webInfo)info; //... ...省略掉具體的業務過程 MutipleThreadResetEvent countdown = web.mre as MutipleThreadResetEvent; countdown.SetOne(); }
等待巡檢線程執行完畢的等待線程,其中執行一些啟用主ui界面控件顯示,進度條控件,按鈕控件等操作,但是彈出的對話框有點問題,是在線程中彈出的,用戶可能關注不到它。
public void WaitThreadEnd(object obj) { MutipleThreadResetEvent countdown = obj as MutipleThreadResetEvent; countdown.WaitAll();
MessageBox.Show("服務器可訪問性驗證已經完成,驗證通過" + js1.ToString() + "個,驗證失敗" + js2.ToString() + "個!", "驗證提示", MessageBoxButtons.OK, MessageBoxIcon.Information); if (btn_start.InvokeRequired) { this.BeginInvoke(new Action<bool>((x) => { btn_start.Enabled = x; PR1.Visible = false; }), true); } }
運行起來后效果還不錯,對於我們這種小白用戶可以解決大部分的問題了。