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方法。

  这些事件处理程序的委托如下:每一个任务都有一个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字段来返回结果给主线程。

在后台线程退出的时候会触发RunWorkerCompleted事件,其事件处理程序会在主线程上执行。RunWorkerCompletedEventArgs参数可以包含已完成后台线程的一些信息,比如返回值以及线程是否被取消了。 如下是代码实现:

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;
        }
    }
}

运行结果如下: 输入图片说明

转载于:https://my.oschina.net/u/1032782/blog/794876

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值