線程封裝組件(BackgroundWorker)和線程(Thread)

      BackgroundWorker是微軟的在.net Framwork中添加的一個組件,主要對線程的訪問提供了一種安全的方式。簡單的說就是對Thread的一次封裝。安全

      BackgroundWorker位於System.ComponentModel下,是一個繼承了Component的組件,微軟官方的解釋爲:Executes an operation on a separate thread.就是說,開始一個新的線程執行操做。app

 

  首先介紹一下BackgroundWorker的相關屬性和方法:異步

  屬性:this

  WorkerReportsProgress:是否能夠報告進度。spa

  WorkerSupportsCancellation:是否容許異步停止。.net

  IsBusy:是否在運行。線程

  CancellationPending:判斷BackgroundWorker是否已經異步取消。code

  方法:blog

  RunWorkerAsync:開始執行任務。觸發DoWork事件繼承

  ReportProgress:異步提醒,觸發ProgressChanged事件,可是這個若是可使用,必須設置WorkerReportsProgress爲True

  CancelAsync:取消BackgroundWorker操做。

  事件:

  DoWork:執行RunWorkerAsync後觸發,異步執行的認爲。

  ProgressChanged:執行ReportProgress時觸發,異步得到進度。

  RunWorkerCompleted:線程結束時觸發,主要有成功結束,發生異常或者取消時發生。

  Thread相對來講就簡單了,可是使用起來就比較麻煩了。Thread位於System.Threading的名空間下,是一個能夠獨立建立和操做一個線程,而且對線程進行設置優先級和得到狀態的一個不可繼承的類。

  下面是我作的一個例子,來比較他們兩個的使用。

  創建一個窗體,放置了兩個TextBox,分別爲設置開始和結束的Progree的值,放置兩個ProgressBar,分別設置爲線程的Progressbar和BackGroundWorker的ProgressBar。另外放置按鈕爲StartBackGroundWorker,StartThread,CancelBackGroundWorker,CancelThread和PauseThread。

  BackGroundWorker的使用就很是簡單:

/// <summary>
        /// Handles the Click event of the btnBackGroundWorker control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void btnBackGroundWorker_Click(object sender, EventArgs e)
        {
            StartFrom = Convert.ToInt32(txtStart.Text);
            EndTo = Convert.ToInt32(txtEnd.Text);

            progressBarThread.Minimum = StartFrom;
            progressBarThread.Maximum = EndTo;

            this.btnBackGroundWorker.Enabled = false;

            this.backgroundWorker.RunWorkerAsync();
        }

        /// <summary>
        /// Handles the DoWork event of the backgroundWorker control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.ComponentModel.DoWorkEventArgs"/> instance containing the event data.</param>
        private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            for (int nValue = StartFrom; nValue <= EndTo; nValue++)
            {
                if (this.backgroundWorker.CancellationPending)
                {
                    e.Cancel = true;
                    return;
                }
                this.backgroundWorker.ReportProgress(nValue);
                Thread.Sleep(200);
            }
        }

        /// <summary>
        /// Handles the ProgressChanged event of the backgroundWorker control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.ComponentModel.ProgressChangedEventArgs"/> instance containing the event data.</param>
        private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.prgProcessBackGroundWorker.Value = e.ProgressPercentage;
        }

        /// <summary>
        /// Handles the RunWorkerCompleted event of the backgroundWorker control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.ComponentModel.RunWorkerCompletedEventArgs"/> instance containing the event data.</param>
        private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            // 取消
            if (e.Cancelled)
            {
                MessageBox.Show("Cancelled");
            }
            // 出現錯誤
            else if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message + Environment.NewLine + e.Error.StackTrace);
            }
            // 完成
            else
            {
                MessageBox.Show("Completed");
                this.btnBackGroundWorker.Enabled = true;
            }
        }

        /// <summary>
        /// Handles the Click event of the btnCancelBackgroundWoker control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void btnCancelBackgroundWoker_Click(object sender, EventArgs e)
        {
            this.backgroundWorker.CancelAsync();
        }

     

     Thread的使用就比較麻煩了,對於尤爲是對異步提醒來講,須要寫委託,代碼量是不少,可是對於BackgroundWorker來講,卻沒有線程暫停和繼續的方法。可是對於通常的來講,這些功能也是不用的,並且在微軟的文檔中還提到了,Thread的Resume和Suspend已經不推薦使用。

// 聲明委託 
        delegate void DelegateType(int x);
       DelegateType TheDelegate;

        // ProgressBar的開始和結束值
        int StartFrom, EndTo;

        // 是否線程暫停
        bool IsThreadPaused;

        ManualResetEvent CancelEvent = new ManualResetEvent(false);
        Thread MyThread;

        /// <summary>
        /// 委託的消息事件
        /// </summary>
        /// <param name="nProgress">進度值</param>
        private void MessageHandler(int nProgress)
        {
            lblThreadStatus.Text = "處理: " + Convert.ToString(nProgress);
            progressBarThread.Value = nProgress;

            if (nProgress == progressBarThread.Maximum)
            {
                MessageBox.Show("Completed");
                this.btnTread.Enabled = true;
            }
        }

        /// <summary>
        /// Handles the Click event of the btnTread control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void btnTread_Click(object sender, EventArgs e)
        {
            TheDelegate = MessageHandler;

            StartFrom = Convert.ToInt32(txtStart.Text);
            EndTo = Convert.ToInt32(txtEnd.Text);

            progressBarThread.Minimum = StartFrom;
            progressBarThread.Maximum = EndTo;

            btnTread.Enabled = false;

            IsThreadPaused = false;
            MyThread = new Thread(ProcessRoutine);
            MyThread.Start();
        }

        /// <summary>
        /// Processes the routine.
        /// </summary>
        private void ProcessRoutine()
        {
            for (int nValue = StartFrom; nValue <= EndTo; nValue++)
            {
                // 判斷是否取消
                if (CancelEvent.WaitOne(0, false) == true)
                {
                    return;
                }
                this.BeginInvoke(this.TheDelegate, nValue);
                Thread.Sleep(200);
            }
        }

        /// <summary>
        /// Handles the Click event of the btnCancelThread control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void btnCancelThread_Click(object sender, EventArgs e)
        {
            btnCancelThread.Enabled = false;
            btnPauseThread.Enabled = false;

            CancelEvent.Set();
            MyThread.Join();
        }

        /// <summary>
        /// Handles the Click event of the btnPauseThread control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void btnPauseThread_Click(object sender, EventArgs e)
        {
            // Bad approach!
            if (!IsThreadPaused)
            {
                IsThreadPaused = true;
                MyThread.Suspend();
                btnPauseThread.Text = "Resume Thread";

                // Disallow Cancel
                btnCancelThread.Enabled = false;
            }
            else
            {
                IsThreadPaused = false;
                MyThread.Resume();
                btnPauseThread.Text = "Pause Thread";
                btnCancelThread.Enabled = true;
            }
        }

比較起來,兩個是徹底相同的,對於Thread來講,靈活性就比較好了,BackgroundWorker的使用就相對來講簡單了。

相關文章
相關標籤/搜索