C#線程運行的機制和原理

BackgroundWorker類能夠簡化線程在後臺執行任務的工做,它具備如下幾種主要成員:併發

屬性:WorkReportsProgress,WorkerSupportsCancellation,IsBusy;方法: RunWorkerAsync( ),CancellAsync( ),ReportProgress( );事件:DoWork,ProgressChanged,RunWorkerCompleted;這幾種主要成員。

WorkReportsProgress以及WorkerSupportsCancellation屬性用於設置是否後臺任務能夠把進度彙報給主線程以及是否支持從主線程取消;IsBusy屬性用來檢查是否正在運行後臺任務。 3種事件用於發送不一樣的程序事件和狀態;後臺線程開始時觸發Dowork事件,後臺任務彙報狀態的時候觸發ProgressChanged事件,後臺工做線程退出的時候觸發RunWorkerCompleted事件。 3種方法用於初始化行爲或改變狀態;調用RunWorkerAsync方法獲取後臺線程而且執行DoWork事件處理程序;調用CancelAsync方法把CancellationPending屬性設置爲True,雖不是必要的,但潛在的取消了線程,DoWork事件處理程序須要檢查這個屬性來決定是否應該中止處理;DoWork事件處理程序,在後臺線程中若是但願向主線程彙報進度時,調用ReportProgress方法。spa

這些事件處理程序的委託以下:每個任務都有一個Object對象的引用做爲第一個參數,以及EventArgs類的特定子類做爲第二個參數
                        void DoWorkEventHandler (object sender, DoWorkEventArgs e)
                        void ProgressChangeEventHandler(object sender, ProgressChangeEventArgs e)
                  void RunWorkerCompletedEventHandler(object sender, RunWorkerCompletedEventArgs e)

當爲這些事件寫附加事件處理程序時,應該以下來使用這些類。線程

從建立BackgroundWorker類的對象並對它進行配置開始,若是但願工做線程爲主線程彙報進度,須要把WorkReportsProgress屬性設置爲ture;若是但願從主線程取消工做線程,就把WorkerSupportsCancellation屬性設置爲true。
  設置好屬性後,就能夠經過調用RunWorkerAsync方法來啓動它,它會開一個後臺線程併發起DoWork事件處理後臺程序。
  在主線程中,若是你已啓用了WorkerSupportsCancellation屬性,而後能夠調用CancelAsync方法,它會設置CancellationPending的屬性爲true,咱們須要在後臺線程DoWork事件處理代碼中檢測這個屬性。

在後臺線程繼續執行任務時,要作如下幾件事情: 若是WorkReportsProgress屬性爲true而且後臺線程要爲主程序彙報進度的話,必須調用BackgroundWorker對象的ReportProgress方法,這時會觸發主線程的ProgressChanged事件,從而運行相應的事件處理程序。 若是WorkerSupportsCancellation屬性爲true,DoWork事件處理代碼應該時時檢測CancellationPending屬性來肯定是否已經取消,如果的話應該退出後臺線程。 若是後臺線程沒有取消,完成了其處理程序,則能夠經過設置DoWorkEventArgs參數的Result字段來返回結果給主線程。code

在後臺線程退出的時候會觸發RunWorkerCompleted事件,其事件處理程序會在主線程上執行。RunWorkerCompletedEventArgs參數能夠包含已完成後臺線程的一些信息,好比返回值以及線程是否被取消了。 以下是代碼實現:orm

using System;
using System.Collections.Generic;
using System.Threading;
using System.Linq;
using System.Text;
using System.ComponentModel;

//線程實現原理
namespace ConsoleApplication2
{
    class DoBackgroundwork
    {
        BackgroundWorker bgWorker = new BackgroundWorker();
        public long BackgroundTotal {get; private set;}
        public bool CompletedNormally {get; private set;}
        
        //構造方法
        public DoBackgroundwork()
        {
            //設置BackgroundWorker屬性
            bgWorker.WorkerReportsProgress = true;
            bgWorker.WorkerSupportsCancellation = true;

            //把處理程序鏈接到BackgroundWorker對象
            bgWorker.DoWork += DoWork_Handler;
            bgWorker.ProgressChanged += ProgressChanged_Handler;
            bgWorker.RunWorkerCompleted += RunWorkerCompleted_Handler;
        }
        public void StartWorker()
        {
            if(!bgWorker.IsBusy)
            {
                bgWorker.RunWorkerAsync();
            }
        }
        、、
        public static long CalculateTheSequence(long value)
        {
            long total = 0;
            for(int i = 0; i < value; ++i)
            {
                total += i;
            }
            return total;
        }
        public void DoWork_Handler(object sender, DoWorkEventArgs args)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            long total = 0;
            for(int i = 0; i <= 5; ++i)
            {
                if(worker.CancellationPending)
                {
                    args.Cancel = true;
                    worker.ReportProgress(-1);
                    break;
                }
                else
                {
                    total += CalculateTheSequence(i * 10000000);
                    worker.ReportProgress(i * 20);
                    Thread.Sleep(300);
                }
            }
            args.Result = total;
        }
        private void ProgressChanged_Handler(object sender, ProgressChangedEventArgs args)
        {
            string output = args.ProgressPercentage == -1
                ? "   Cancelled"
                : string.Format("               {0}%", args.ProgressPercentage);
            System.Console.WriteLine(output);
        }
        private void RunWorkerCompleted_Handler(object sender, RunWorkerCompletedEventArgs args)
        {
            CompletedNormally = !args.Cancelled;
            BackgroundTotal = args.Cancelled ? 0 : (long)args.Result;
        }
        public void Cancel()
        {
            if(bgWorker.IsBusy)
            {
                bgWorker.CancelAsync();
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            GiveInstructionsToTheUser();
            OutputTheSummaryHeaders();
            DoBackgroundwork bgw = new DoBackgroundwork();
            bgw.StartWorker();
            long mainTotal = 0;
            for (int i = 0; i < 5; ++i)
            {
                if (Program.CheckForCancelInput())
                {
                    bgw.Cancel();
                }
                mainTotal += DoBackgroundwork.CalculateTheSequence(100000000);
                Thread.Sleep(200);
                System.Console.WriteLine("     {0}%", (i + 1) * 20);
            }
            SummarizeResults(bgw, mainTotal);
            System.Console.ReadLine();
        }
        private static void GiveInstructionsToTheUser()
        {
            System.Console.WriteLine("Press <Enter> to start.");
            System.Console.ReadLine();
        }
        private static void OutputTheSummaryHeaders()
        {
            System.Console.WriteLine("   Main    Background ");
            System.Console.WriteLine("---------------------");
        }
        private static void SummarizeResults(DoBackgroundwork bgw, long mainTotal)
        {
            if (bgw.CompletedNormally)
            {
                System.Console.WriteLine("\nBackground Completed Normally");
                System.Console.WriteLine("Background Total = {0}.", bgw.BackgroundTotal);
            }
            else
            {
                System.Console.WriteLine("\nBackground Cancelled.");
            }
            System.Console.WriteLine("Main Total ={0}.", mainTotal);
        }
        private static bool CheckForCancelInput()
        {
            bool doCancel = Console.KeyAvailable;
            if (doCancel)
            {
                Console.ReadKey();
            }
            return doCancel;
        }
    }
}

運行結果以下: 輸入圖片說明對象

相關文章
相關標籤/搜索