C# .NET 使用SynchronizationContext访问主线程
项目场景:
项目场景:WindowsFrom或WPF项目中不方便使用到控件的Invoke方法时,可以使用WindowsBase.dll下的System.Thread.SynchronizationContext
问题描述
很多人不了解什么是主线程,即具有Context的线程,他的设计是为了提高用户与屏幕的交互效率,进而提高用户体验。
原因分析:
有时候我们开发的桌面UI应用莫名卡顿了,一般是其他数据来源
属于其他线程
,但我们使用其他线程操作UI时就会出现卡顿的情况。
解决方案:
具体解决方案:
- 首先定义可同步的主线程
SynchronizationContext
上下文引用介质
SynchronizationContext SyncContext = null;
- 第二步:在需要的地方使用上下文引用介质
SyncContext
的Post方法
protected void initPortReceive()
{
SyncContext.Post(change, "Subscription receiving catch error");
}
- 第三步:UI中显示数据
private void change(object str)
{
showTips(str.ToString());
}
桌面应用运行效果如下:
测试运行36小时,未发生异常.且软件效果流畅。
原理解析
概念
在 .NET 框架的多线程程序中,往往很多时间需要将一个线程工作单元或上下文,传递给另一个线程。我们都知道的是 Windows 上的程序是以 消息循环为中心的,这个如何理解呢?
每一个 window 窗体都有一个与之关联的
Window Procedure
这个是一个用来处理所有消息发送或发送到类的给所有消息的函数。窗体的所有UI显示
和显示都取决于 Window Procedure
对这些消息的响应。
SynchronizationContext 主要提供了一下三方面的功能:
-
提供了一种把工作单元 添加到 上下文的队列中的方法。
-
每一个线程 都有 一个 “current” 的 上下文。
-
它保存着未完成异步操作数的计数
计数
这个数量 随着 当前的 SC 被捕获,或被夺取时增加,当捕获的 SC 用于将完成通知排队发送到该上下文时,则减少
。
重要的 SynchronizationContext APIClass
{
// Dispather work to the context.
void Post(); // Asynchronously
void send(); // Synchronously
// Keep track of the number of asynchronous operations.
void OperationStarted();
void OperationCompleted();
// Each thread has a current context.
// If "Current" is null, then the thread's current context is
// "new SynchronizationContext()", by convention.
static SynchronizationContext Current{get;}
static void SetSynchronizationContext(SynchronizationContext);
}
SynchronizationContext 的实现
WindowsFormsSynchronizationContext (System.Windows.Forms.dll)
-
Use ISynchronizeInvoke on UI Control,用来将委托传递 给 win32 message loop
-
每一个 UI 线程 都会创建一个 WindowsFormsSynchronizationContext
-
WindowsFormsSynchronizationContext 的上下文是一个 单一的UI 线程
DispatcherSynchronizationContext(WindowsBase.dll: System.Windows.Threading)
-
以 “Normal” 优先级的委托 传递给 UI 线程。
-
所有排队到 DispatcherSynchronizationContext 的委托都是由 特定的UI线程 按照他们排队的顺序 依次执行,一次执行一个。
-
DispatcherSynchronizationContext 的上下文是一个 单一的 UI 线程
Default(ThreadPool) SynchronizationContext(mscorlib.dll: System.Threading)
-
默认的 SynchronizationContext 是一个默认构造函数的 SynchronizationContext 对象,按照惯例,如果一个线程 当前的 SynchronizationContext 是 null,那么它会 隐式的 含有一个 默认的 SynchronizationContext。
-
默认 SynchronizationContext 将它的异步委托 添加到 线程池 队列,但是 在调用的线程上执行它的同步委托。因此,它的上下文 涵盖了 所有的线程池的线程 以及 调用它的线程。上下文 “借用” 调用它的线程,然后把它们带入到上下文中 直到委托结束。从某种意义上来说,默认上下文可能包含当前进程中的任何线程。
-
默认 SynchronizationContext 是应用在 线程池中的线程的除非是被 ASP.NET 托管的代码,默认的 SynchronizationContext 也隐式应用于显式的子线程中除非子线程设置了自己的 SynchronizationContext。因此,UI 的应用一般都有两个 SynchronizationContext, UI 的 SynchronizationContext cover UI thread, default SynchronizationContext cover ThreadPool thread。
图1 是一个典型比如 WPF 程序,调用 Dispatcher.Invoke 或 Dispatcher.BeginInvoke 时Context 转换的一个图。
private void On_Time_Elapsed(object sender, EventArgs e)
{
Dispatcher.Invoke(()=>{
_displayTextBlock.Text = "Show Here.";
});
}
图2 是 WPF 程序中,Dispatcher.Invoke 中又新开了线程池的线程执行的例子。
private void On_Time_Elapsed(object sender, EventArgs e){
Dispatcher.Invoke(()=>{
Task.Run(()=>{
// Do Something here.
});
_displayTextBlock.Text = "1111";
});
}
相关文章
- 使用 Visual Studio 部署 .NET Core 应用 ——.Net Core 部署到Ubuntu 16.04
- C#.NET常见问题(FAQ)-如何声明list的多维数组
- C#.NET常见问题(FAQ)-如何使用2D绘图控件ZedGraph绘制坐标轴和坐标曲线
- C#.NET常见问题(FAQ)-控制台程序如何输出Messagebox
- C#.NET常见问题(FAQ)-如何在系统变量中加入新的环境变量
- C#.NET常见问题(FAQ)-程序如何单步调试和设置断点
- C#.NET下转换泛型列表为JSON格式
- 重学c#系列——动态类型[二十二]
- c# 线程的优先级
- c# 优化代码的一些规则——使用is或as和强制类型转换的区别[三]
- C# 获取选择文件信息
- C# 中的.pdb/ .vshost.exe/ .vshost.exe.manifest文件
- C#内存流示例----->用内存流来读取图片
- C#开发之反射的简单使用
- C# 中winform的一些属性设置
- Atitit.java c#.net php项目中的view复用(jsp,aspx,php的复用)
- atitit.跨语言实现备份mysql数据库 为sql文件特性 api 兼容性java c#.net php js
- atitit. 文件上传带进度条 atiUP 设计 java c# php
- Atitit.c# .net 3.5 4.0 4.5 5.0 6.0各个版本新特性战略规划总结
- Atitit. 悬浮窗口的实现 java swing c# .net c++ js html 的实现
- Atitit. .net c# web 跟客户端winform 的ui控件结构比较
- c# 小叙 Encoding(三)
- VB.NET与C# 语法show差异
- C# visual studio 自动换行
- C# 构造函数的使用方法
- C#数字图像处理图像旋转图片加角度
- 10分钟学会Visual Studio将自己创建的类库打包到NuGet进行引用(net,net core,C#)
- C#习题五