BackgroundWorker类位于System.ComponentModel命名空间下,主要用来异步执行一个长时间的操作,然后,在完成事件中安全更新UI的控件属性。UI中的控件是不允许非创建该控件的线程修改的。典型用法如下:

BackgroundWorker m_worker = new BackgroundWorker();
// 设置支持进度报告、异步取消功能,默认都为false
m_worker.WorkerReportsProgress = true;
m_worker.WorkerSupportsCancellation = true; // 绑定事件
m_worker.DoWork += m_worker_DoWork;
m_worker.ProgressChanged += m_worker_ProgressChanged;
m_worker.RunWorkerCompleted += m_worker_RunWorkerCompleted; void m_worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
if (e.Cancelled == true) {
// 处理取消
return;
} else if (e.Error != null) {
// 处理异常
return;
} // 在UI中显示结果
// txtBox.Text = e.Result.ToString();
} void m_worker_ProgressChanged(object sender, ProgressChangedEventArgs e) {
//progressBar.Value = e.ProgressPercentage;
} void m_worker_DoWork(object sender, DoWorkEventArgs e) {
BackgroundWorker sendWorker = sender as BackgroundWorker; for (int i = ; i < ; i++) {
// 做异步工作。。。。 // 报告进度
sendWorker.ReportProgress(i); // 请求取消工作内容
if (sendWorker.CancellationPending == true) {
e.Cancel = true;
return;
}
} // 可选,设置异步工作结果
e.Result = GetResultData();
}

它的实现原理最重要的只有两点:

一点是用异步委托间接使用线程池执行长时间的操作;

另外一点是通过AsyncOperationManager和AsyncOperation对调用RunWorkerAsync的线程SynchronizationContext进行抽象;

BackgroundWorker的源码参见 http://www.projky.com/dotnet/4.5.1/System/ComponentModel/BackgroundWorker.cs.html

首先从它的构造函数开始:

private delegate void WorkerThreadStartDelegate(object argument);

private AsyncOperation                      asyncOperation = null;
private readonly WorkerThreadStartDelegate threadStart;
private readonly SendOrPostCallback operationCompleted;
private readonly SendOrPostCallback progressReporter; public BackgroundWorker()
{
threadStart = new WorkerThreadStartDelegate(WorkerThreadStart);
operationCompleted = new SendOrPostCallback(AsyncOperationCompleted);
progressReporter = new SendOrPostCallback(ProgressReporter);
}

定义了一个私有的委托类型WorkerThreadStartDelegate,以便于在该委托类型对象上直接调用BaginInvoke到线程池执行委托。SendOrPostCallback 是方便在UI线程(本质是调用RunWorkAsync时捕获的当前线程同步上下文对象,为了容易理解,就叫它UI线程)上执行回调而创建的。而asyncOperation则通过Post方法在UI线程上异步来执行SendOrPostCallback委托。

在对DoWork添加事件后,需要调用RunWorkerAsync,有两个重载,但我们只关注最后一个带参数的:

public void RunWorkerAsync(object argument)
{
if (isRunning)
{
throw new InvalidOperationException(SR.GetString(SR.BackgroundWorker_WorkerAlreadyRunning));
} isRunning = true;
cancellationPending = false; asyncOperation = AsyncOperationManager.CreateOperation(null);
threadStart.BeginInvoke(argument,
null,
null);
}

其实,asyncOperation = AsyncOperationManager.CreateOperation(null);这一行代码,等同于下面的代码:

if (SynchronizationContext.Current == null) {
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
}
SynchronizationContext currentContext = SynchronizationContext.Current;
asyncOperation = AsyncOperation.CreateOperation(null, currentContext)

简单来说,就是获得当前的SynchronizationContext的对象,如果不存在,则创建一个默认的(基于线程池实现的)。并让asyncOperation拥有SynchronizationContext的引用。

在.NET中,有很多种SynchronizationContext的子类,比如Winform里面的WindowsFormsSynchronizationContext类,WPF里面的DispatcherSynchronizationContext类,ASP.NET里面的AspNetSynchronizationContext类。重点是,当在Winform的UI线程中访问SynchronizationContext.Current属性,获得的就是WindowsFormsSynchronizationContext的对象。

那么,最终,AsyncOperation的Post方法,就是直接调用SynchronizationContext的Post方法,来实现在UI中回调的目的。

public void Post(SendOrPostCallback d, object arg)
{
VerifyNotCompleted();
VerifyDelegateNotNull(d);
syncContext.Post(d, arg);
}

还有一点,threadStart.BeginInvoke会用线程池中的线程执行类似如下的代码:

object workerResult = null;
Exception error = null;
bool cancelled = false; try
{
DoWorkEventArgs doWorkArgs = new DoWorkEventArgs(argument);
DoWorkEventHandler handler = (DoWorkEventHandler)(Events[doWorkKey]);
if (handler != null)
{
handler(this, doWorkArgs);
}
if (doWorkArgs.Cancel)
{
cancelled = true;
}
else
{
workerResult = doWorkArgs.Result;
}
}
catch (Exception exception)
{
error = exception;
} RunWorkerCompletedEventArgs e =
new RunWorkerCompletedEventArgs(workerResult, error, cancelled); asyncOperation.PostOperationCompleted(operationCompleted, e);

其中,对DoWork事件的声明如下:

private static readonly object doWorkKey = new object();

public event DoWorkEventHandler DoWork{
add{
this.Events.AddHandler(doWorkKey, value);
}
remove{
this.Events.RemoveHandler(doWorkKey, value);
}
}

Events是从Component下派生来的protected EventHandlerList对象。

从BackgroundWorker的实现可以看出,它的实现是普遍性的,并不一定要用在Winform或者WPF中。

本文引用的源码参考列表可以从扣丁格鲁上查看。

http://www.projky.com/dotnet/4.5.1/System/ComponentModel/BackgroundWorker.cs.html

http://www.projky.com/dotnet/4.5.1/System/ComponentModel/AsyncOperation.cs.html

http://www.projky.com/dotnet/4.5.1/System/ComponentModel/AsyncOperationManager.cs.html

http://www.projky.com/dotnet/4.5.1/System/Threading/SynchronizationContext.cs.html

http://www.projky.com/dotnet/4.5.1/System/Windows/Forms/WindowsFormsSynchronizationContext.cs.html

http://www.projky.com/dotnet/4.5.1/System/Windows/Threading/DispatcherSynchronizationContext.cs.html

http://www.projky.com/dotnet/4.5.1/System/Web/AspNetSynchronizationContext.cs.html

关于基于事件的异步编程设计模式EAP更多参考请见http://msdn.microsoft.com/zh-cn/library/hkasytyf(v=vs.110).aspx

BackgroundWorker原理剖析的更多相关文章

  1. ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件)

    ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件) Startup Class 1.Startup Constructor(构造函数) 2.Configure ...

  2. ASP.NET Core 运行原理剖析1:初始化WebApp模版并运行

    ASP.NET Core 运行原理剖析1:初始化WebApp模版并运行 核心框架 ASP.NET Core APP 创建与运行 总结 之前两篇文章简析.NET Core 以及与 .NET Framew ...

  3. 【Xamarin挖墙脚系列:Xamarin.IOS机制原理剖析】

    原文:[Xamarin挖墙脚系列:Xamarin.IOS机制原理剖析] [注意:]团队里总是有人反映卸载Xamarin,清理不完全.之前写过如何完全卸载清理剩余的文件.今天写了Windows下的批命令 ...

  4. 【Xamarin 跨平台机制原理剖析】

    原文:[Xamarin 跨平台机制原理剖析] [看了请推荐,推荐满100后,将发补丁地址] Xamarin项目从喊口号到现在,好几个年头了,在内地没有火起来,原因无非有三,1.授权费贵 2.贵 3.原 ...

  5. iPhone/Mac Objective-C内存管理教程和原理剖析

    http://www.cocoachina.com/bbs/read.php?tid-15963.html 版权声明 此文版权归作者Vince Yuan (vince.yuan#gmail.com)所 ...

  6. 【Xamain 跨平台机制原理剖析】

    原文:[Xamain 跨平台机制原理剖析] [看了请推荐,推荐满100后,将发补丁地址] Xamarin项目从喊口号到现在,好几个年头了,在内地没有火起来,原因无非有三,1.授权费贵 2.贵 3.原生 ...

  7. Python字符串原理剖析------万恶的+号

    字符串原理剖析pyc文件,执行python代码时,如果导入了其他的.py文件,那么执行过程中会自动生成一个与其同名的.pyc文件,该文件就是python解释器变异之后产生的字节码 PS:代码经过编译可 ...

  8. MapReduce/Hbase进阶提升(原理剖析、实战演练)

    什么是MapReduce? MapReduce是一种编程模型,用于大规模数据集(大于1TB)的并行运算.概念"Map(映射)"和"Reduce(归约)",和他们 ...

  9. ASP.NET Core 运行原理剖析

    1. ASP.NET Core 运行原理剖析 1.1. 概述 1.2. 文件配置 1.2.1. Starup文件配置 Configure ConfigureServices 1.2.2. appset ...

随机推荐

  1. Android_字符串转换

    这个很简单,只是一个输入框,一个按钮,一个TextView用来显示转换后的字符串,按钮有一个事件,使用可视化操作界面下添加的,毕竟很方便嘛!

  2. c++面试题中经常被面试官面试的小问题总结(一)(本篇偏向基础知识)

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/10711810.html 1.类中的函数定义后加了一个const代表什么? 代表它将具备以下三个 ...

  3. Redis笔记(七):Redis应用场景

    特性优势 1 支持持久化 Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用. 2 数据类型丰富 Redis不仅仅支持简单的key-value类型的数据,同时还 ...

  4. Java运用第三方开源jar包sigar.jar获取服务器信息

    通过使用第三方开源jar包sigar.jar我们可以获得本地的信息 一.准备工作 (1)下载jar包和相关文件 资源链接:百度云:链接:https://pan.baidu.com/s/1nxccJHJ ...

  5. Python jieba库的使用说明

    1.jieba库基本介绍 (1).jieba库概述 jieba是优秀的中文分词第三方库 - 中文文本需要通过分词获得单个的词语         - jieba是优秀的中文分词第三方库,需要额外安装 - ...

  6. 我是怎么从安卓到php再成为前端开发工程师的

    记得我下定决心学Android(安卓)是17年的暑假,暑假前,学校组织了一次集训,美其名曰帮我们巩固知识,实际上就是学校和长沙的培训学校某牛达成了合作,教我们一些基础知识,然后集训完建议那些在学校没学 ...

  7. [转载]常见的移动端H5页面开发遇到的坑和解决办法

    转过来,平时看看.虽然还有很多问题至今无解.比如:华为麒麟950的P8和meta打开我们的应用首页经常偶发白屏.!! 1.安卓浏览器看背景图片,有些设备会模糊. 用同等比例的图片在PC机上很清楚,但是 ...

  8. HTML5中Access-Control-Allow-Origin解决跨域问题

    www.111cn.net 更新:2015-01-07 编辑:flyfox 来源:转载 跨域在开发中一些是一个比较常见的问题虽然有json或者xml来解决,现在html5开始流行了,我们可以通过Acc ...

  9. 啰里吧嗦式讲解java静态代理动态代理模式

    一.为啥写这个 文章写的比较啰嗦,有些东西可以不看,因为想看懂框架, 想了解SSH或者SSM框架的设计原理和设计思路, 又去重新看了一遍反射和注解, 然后看别人的博客说想要看懂框架得先看懂设计模式,于 ...

  10. 【转】Apache服务器的下载与安装

    PHP的运行必然少不了服务器的支持,何为服务器?通俗讲就是在一台计算机上,安装个服务器软件,这台计算机便可以称之为服务器,服务器软件和计算机本身的操作系统是两码事,计算机自身的操作系统可以为linux ...