Excel的线程 与 SynchronizationContext的实现
COM组件的线程模型与Excel多线程的背景知识
COM组件的线程模型被称之为Apartment模型,COM对象初始化时其执行上下文(Execution Context),他要么和单个线程关联STA(Single Thread Apartment ) 要么和多个线程关联MTA(Multi Thread Apartment)。Excel是一种STA线程的应用程序,使用多线程直接怼会出问题,必须借助线程的同步上下文实现线程间的消息传递。
1、Excel 开发中与线程相关的若干问题参考这个链接:
2、SynchronizationContext的实现参考这个链接(共3篇文章,进入链接后可以找到下一章的链接):
https://www.codeproject.com/Articles/31971/Understanding-SynchronizationContext-Part-I
3、ExcelDNA是什么
Excel-DNA is an independent project to integrate .NET into Excel. With Excel-DNA you can make native (.xll) add-ins for Excel using C#, Visual Basic.NET or F#, providing high-performance user-defined functions (UDFs), custom ribbon interfaces and more. Your entire add-in can be packed into a single .xll file requiring no installation or registration.
4、ExcelDNA下实现一个自定义的SynchronizationContext
https://groups.google.com/forum/#!searchin/exceldna/synchronizationcontext%7Csort:date/exceldna/pyybn0lSP8k/3DW6NOekCgAJ
ExcelDNA中的解决方案
dynamic app;
dynamic worksheet; public void Test(IRibbonControl ribbonControl)
{
app = ExcelDnaUtil.Application;
worksheet = app.ActiveSheet;
worksheet.Cells[, ].Value = Thread.CurrentThread.ManagedThreadId;
Action<object> action = Run;
Task task = new Task(action,ExcelSynchronizationContext.Current);
task.Start(); }
private void Run(object context)
{
worksheet.Cells[, ].Value = Thread.CurrentThread.ManagedThreadId; for (int i = ; i < ; i++)
{
Thread.Sleep();
ExcelAsyncUtil.QueueAsMacro(UpdateUI, i);
}
} private void UpdateUI(object state)
{
int i = (int)state + ;
worksheet.Cells[i, ].Value = i;
worksheet.Cells[i, ].Value = Thread.CurrentThread.ManagedThreadId;
}
Task task = new Task(action,ExcelSynchronizationContext.Current); ExcelSynchronizationContext.Current为主线程的SynchronizationContext。
ExcelAsyncUtil.QueueAsMacro(UpdateUI, i); 其实是执行了SynchronizationContext的Post方法。 上面是ExcelDNA里集成的SynchronizationContext实现,有兴趣可以→ 尝试实现自定义一个SynchronizationContext
一个SendOrPostCallbackItem实例为一组SendOrPostCallback委托与方法、参数
internal enum ExecutionType
{
Post,
Send
}
internal class SendOrPostCallbackItem
{
object state;
ExecutionType executionType;
SendOrPostCallback callbackMethod; internal SendOrPostCallbackItem(SendOrPostCallback callback, object state, ExecutionType executionType)
{
this.callbackMethod = callback;
this.state = state;
this.executionType = executionType;
} internal void Execute()
{
if (executionType == ExecutionType.Post)
Post();
else
Send();
}
internal void Send()
{
throw new NotImplementedException();
} internal void Post()
{
callbackMethod(state);
}
}
DiyExcelSynchronizationContext,在ExcelDNA下实现一个SynchronizationContext
public class DiyExcelSynchronizationContext : SynchronizationContext
{
private const string RunMacroName = "ExcelSyncContext.Run";
private static readonly ConcurrentQueue<SendOrPostCallbackItem> queue = new
ConcurrentQueue<SendOrPostCallbackItem>();
private static readonly TimeSpan BackoffTime = TimeSpan.FromSeconds();
[ExcelCommand(Name = RunMacroName)]
public static void Run()
{
while (true)
{
SendOrPostCallbackItem workItem;
if (!queue.TryDequeue(out workItem))
{
return;
}
workItem.Execute();
}
}
dynamic application = ExcelDnaUtil.Application;
public override void Post(SendOrPostCallback d, object state)
{ SendOrPostCallbackItem item = new SendOrPostCallbackItem(d, state, ExecutionType.Post);
queue.Enqueue(item);
Task.Factory.StartNew(() =>
{
while (true)
{
try
{
application.Run(RunMacroName);
break;
}
catch (COMException e1)
{
if (IsRetry(e1))
{
Thread.Sleep(BackoffTime);
continue;
}
return;
}
catch (Exception e2)
{
return;
}
} });
}
public const uint RPC_E_SERVERCALL_RETRYLATER = 0x8001010A;
public const uint RPC_E_CANTCALLOUT_INASYNCCALL = 0x800AC472; public static bool IsRetry(COMException e)
{
var errorCode = (uint)e.ErrorCode;
switch (errorCode)
{
case RPC_E_SERVERCALL_RETRYLATER:
case RPC_E_CANTCALLOUT_INASYNCCALL:
return true;
default:
return false;
}
}
}
Excel的线程 与 SynchronizationContext的实现的更多相关文章
- 浅谈Excel开发:十 Excel 开发中与线程相关的若干问题
采用VSTO或者Shared Add-in等技术开发Excel插件,其实是在与Excel提供的API在打交道,Excel本身的组件大多数都是COM组件,也就是说通过Excel PIA来与COM进行交互 ...
- 利用SynchronizationContext.Current在线程间同步上下文
简而言之就是允许一个线程和另外一个线程进行通讯,SynchronizationContext在通讯中充当传输者的角色.另外这里有个地方需要清楚的,不是每个线程都附加SynchronizationCon ...
- 利用SynchronizationContext.Current在线程间同步上下文(转)
https://blog.csdn.net/iloli/article/details/16859605 简而言之就是允许一个线程和另外一个线程进行通讯,SynchronizationContext在 ...
- 浅谈Excel开发:六 Excel 异步自定义函数
上文介绍了Excel中的自定义函数(UDF ),它极大地扩展了Excel插件的功能,使得我们可以将业务逻辑以Excel函数的形式表示,并可以根据这些细粒度的自定义函数,构建各种复杂的分析报表. 普通的 ...
- 搞懂 SynchronizationContext(第一部分)【翻译】
SynchronizationContext -MSDN 很让人失望 我不知道为什么,目前在.Net下关于这个类只有很少的资料.MSDN文档也只有很少的关于如何使用SynchronizationCon ...
- 搞懂 SynchronizationContext
SynchronizationContext -MSDN 很让人失望 我不知道为什么,目前在.Net下关于这个类只有很少的资料.MSDN文档也只有很少的关于如何使用SynchronizationCon ...
- await之后的线程问题
之前看了园子里的一篇文章「async & await的前世今生」,收益颇多.而其中有句话被博主特意用红色标注,所以留意多看了几眼,「await 之后不会开启新的线程(await 从来不会开启新 ...
- 重新想象 Windows 8 Store Apps (48) - 多线程之其他辅助类: SpinWait, SpinLock, Volatile, SynchronizationContext, CoreDispatcher, ThreadLocal, ThreadStaticAttribute
[源码下载] 重新想象 Windows 8 Store Apps (48) - 多线程之其他辅助类: SpinWait, SpinLock, Volatile, SynchronizationCont ...
- C# Winform 跨线程更新UI控件常用方法汇总(多线程访问UI控件)
概述 C#Winform编程中,跨线程直接更新UI控件的做法是不正确的,会时常出现“线程间操作无效: 从不是创建控件的线程访问它”的异常.处理跨线程更新Winform UI控件常用的方法有4种:1. ...
随机推荐
- JavaFX教程
JavaFX是Java的下一代图形用户界面工具包.JavaFX是一组图形和媒体API,我们可以用它们来创建和部署富客户端应用程序. JavaFX允许开发人员快速构建丰富的跨平台应用程序.JavaFX通 ...
- linux 下安装与使用
一 安装 ## 先用wget下载源文件 wget http://download.redis.io/releases/redis-3.2.9.tar.gz ## 我自己建个文件夹 mkdir /usr ...
- JavaScript之 ------ 函数(一般函数、动态函数、匿名函数)
JavaScript之 ------ 函数(一般函数.动态函数.匿名函数) 函数 一.一般函数 1.格式: function 函数名(形式参数...) { 执行语句: return 返回值: } 函数 ...
- (4.20)sql server分离附加操作
关键词:sql server分离.sql server附加.分离附加.sql server附加分离 [0].数据库分离.附加的说明 SQL Server提供了“分离/附加”数据库.“备份/还原”数据库 ...
- 给Laravel4添加中文语系(转)
Laravel 4 官方不附带英文以外的 validataion 错误信息翻译. 今天发现GitHub 上有一个 repository 收集不同的翻译,大家可以下载需要的翻译. GitHub项目地址: ...
- 详解 Flexible Box 中的 flex 属性
导读: 弹性盒子是 CSS3 的一种布局模式,一种当页面需要适应不同的屏幕大小以及设备类型时确保元素拥有适当的行为的布局方式.其中 flex 属性用于指定弹性子元素如何分配空间. flex 属性的值 ...
- HashSet源码解析笔记
HashSet是基于HashMap实现的.HashSet底层采用HashMap来保存元素,因此HashSet底层其实比较简单. HashSet是Set接口典型实现,它按照Hash算法来存储集合中的元素 ...
- ASE团队项目alpha阶段Frontend组 scrum2 记录
ASE团队项目alpha阶段Frontend组 scrum2 记录 本次会议于11.5日, 11:30在微软北京西二楼13158研讨室,讨论持续15分钟 与会人员:Jingyi Xie, Jiaqi ...
- 如何在mysql数据库中开启使用tab键补全功能
声明:数据库tab键补全的是表名,列名,数据库名,不是数据库中的命令,变量等 永久支持tab键补全[root@localhost ~]# vim /etc/my.cnf添加以下两行:[mysql]au ...
- 同一子网建立ssh通道,映射到本地
在办公室有一台机器连入同一子网络,开启jupyter-notebook但是只能在这台机器上访问到,怎样可以在家也可以访问呢? 此时最简单的方法是在本地建立一个ssh通道: 在本地终端中输入 ssh u ...