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. ...
随机推荐
- Qt 打开指定网站/系统文件夹
本文转载自:http://blog.csdn.net/robertkun/article/details/7802977和http://hi.baidu.com/xyhouse/item/ccf ...
- [已解决]报错: No module named pip
cmd中敲命令: python -m ensurepip 更新升级pip命令: python -m pip install --upgrade pip
- WPF 动态添加控件以及样式字典的引用(Style introduction)
原文:WPF 动态添加控件以及样式字典的引用(Style introduction) 我们想要达到的结果是,绑定多个Checkbox然后我们还可以获取它是否被选中,其实很简单,我们只要找到那几个关键的 ...
- js保留两位小数的方法
js保留两位小数的方法如下 1.toFixed()方法 需注意,保留两位小数,将数值类型的数据改变成了字符串类型 2.Math.floor(),不四舍五入 ,向下取整 注意,不改变数据类型 3.字符串 ...
- teb教程2
http://wiki.ros.org/teb_local_planner/Tutorials/Inspect%20optimization%20feedback 检查优化反馈 简介:怎样检查优化的轨 ...
- 杭电多校第四场-H- K-th Closest Distance
题目描述 You have an array: a1, a2, , an and you must answer for some queries.For each query, you are g ...
- KMP 算法学习
KMP算法是用来做字符串匹配的.关于字符串匹配,最简单最容易想到的方法是暴利查找,使用双重for循环处理. 该方法的时间复杂度为O((n-m+1)*m) (n为目标串T长度,m为模式串P长度, 从T中 ...
- vue-cli 项目配置
vue viewport <meta name="viewport" content="width=device-width,initial-scale=1,min ...
- NX二次开发-Block UI C++界面Body Collector(体收集器)控件的获取(持续补充)
Body Collector(体收集器)控件的获取 NX9+VS2012 #include <uf.h> #include <uf_obj.h> UF_initialize() ...
- 汇编检测OD代码
repnz指令说明:重复执行其后面的指令,CX或ECX存放最多比较次数,DI或EDI存放查找表首地址,AL或AX或EAX存放想查找的内容.当(CX或ECX)= 0 或 ZF=1 退出重复,否则,(CX ...