C#线程运行的机制和原理
2016-11-27 09:54
183 查看
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类的特定子类作为第二个参数。
voidDoWorkEventHandler (object sender, DoWorkEventArgs e)
voidProgressChangeEventHandler(object sender, ProgressChangeEventArgs e)
voidRunWorkerCompletedEventHandler(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参数可以包含已完成后台线程的一些信息,比如返回值以及线程是否被取消了。
代码实现如下:
属性: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类的特定子类作为第二个参数。
voidDoWorkEventHandler (object sender, DoWorkEventArgs e)
voidProgressChangeEventHandler(object sender, ProgressChangeEventArgs e)
voidRunWorkerCompletedEventHandler(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; } } }
相关文章推荐
- C#线程运行的机制和原理
- 利用C#线程机制实现应用程序的单实例运行
- 利用C#线程机制实现应用程序的单实例运行
- 利用C#线程机制实现应用程序的单实例运行
- Windows运行机理——线程的机制(2)
- Windows运行机理——线程的机制(4)
- C# 挂起恢复运行线程代码
- ASP.NET运行原理/运行机制
- ajax的原理和运行机制 【转载慕容】
- ASP.NET的运行原理与运行机制
- C# 挂起恢复运行线程代码
- C++类的静态成员函数在多线程的工作机制以及运行过程中强制结束线程实验
- Ajax的原理和运行机制
- C#的多线程机制探索(三)—线程的同步和通讯(生产者和消费者)
- C#的多线程机制探索(二)—操纵一个线程
- C# 挂起恢复运行线程代码
- Windows运行机理——线程的机制(3)
- ajax的原理和运行机制
- MFC框架原理以及消息运行机制
- C#带有消息机制的线程 - CustomMessageQueue [翻译自wuyazhe的VB版本]