1. 程式人生 > 實用技巧 >C#多執行緒中等待執行緒池中的所有執行緒執行完畢後再執行下一個執行緒

C#多執行緒中等待執行緒池中的所有執行緒執行完畢後再執行下一個執行緒

網上找的,做個筆記記錄一下。

有這麼一個需求,就是巡檢多臺伺服器是否都線上,點選巡檢按鈕後,按行讀取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); } }

執行起來後效果還不錯,對於我們這種小白使用者可以解決大部分的問題了。