简单理解线程同步上下文
为了线程安全,winform和wpf框架中规定只能使用UI线程操作控件,从其它线程上操作控件就会报跨线程异常。假如有这样一个场景:点击按纽,然后开始计算员工薪资,并将计算信息实时展示在一个文本框中,由于计算过程比较耗时,为了不让界面卡死,我们会将计算方法放在单独一个线程中。UI代码如下:
薪资计算类代码如下:
上面的代码就不过多解释了,相信大家都看的懂。按纽点击后,开启一个新线程,执行计算,并将更新UI的方法以委托的形式传给SalaryCalculator类。我们执行一下,如下:
不出意外,报错了,我们不能在新线程中更新UI线程。一般的做法,我们可以使用Invoke,这个大家应该都用烂了。改写下ShowMessage,代码如下:
除了以上办法,我们还可以使用SynchronizationContext来解决上面的问题。这个类,大家可能比较陌生, 我们来看一下它的定义,如下:
它的定义:提供在各种同步模型中传播同步上下文中的基本功能。其实它的含义就是对当前线程上下文的封装,或者叫当前线程所在环境的封装。封装的对象可以传递至其他线程,然后在其他线程中调用其Post或Send方法,以此来实现线程间的消息传播。我们使用SynchronizationContext修改上面的代码,得到的结果都是一样。代码如下:
上面的代码中,先通过SynchronizationContext.Current获取UI线程的同步上下文对象,然后在计算薪资的线程中使用这个对象的Post方法,这时控制是在UI线程的上下文中执行,所以不会报错。
讲到这里,其实SynchronizationContext的内容就讲完了,不过有个点可以再补充下。大家应该知道Task对象有一个ConfigureAwait()方法,用来配置是否同步上下文,我们到这个方法中看一下,代码如下:
continueOnCapturedContext尝试将延续任务封送回原始上下文件,默认为true。这里说的原始上下文,其实就是SynchronizationContext,即异步前(await)前所在的线程的同步上下文。我们将Calculate改成异步方法,代码如下:
我们知道,异步方法在遇到await之前都在当前线程中执行,当执行完await这行后,方法就会退出,然后会将await之后的代码封装成委托(可能不太准确,大概这个意思,会产生一个状态机类,不展开讨论)。在执行await时,默认会捕获当前的线程上下文,然后当执行完Task.Delay(1000)后,上面说的线程上下文就会将剩下的代码发回(Post/Send)自己的线程执行。大概像下面这个样子,代码如下:
上面代码不一定准确,只是想表达这个意思。如果我们不想剩下来的代码在原来的上下文中执行,可以将continueOnCapturedContext设为false,这也是微软推荐的做法。不然会出现一些意想不到的情况,比如死锁。我们看一下调用的地方,代码如下:
我们配置了不捕获上下文,这时代码是正常运行的。我们再来演示一下经典的死锁问题吧,如果你还有兴趣就接着向下看吧。我们改造下上面的代码,改成同步等待,并默认捕获上下文。代码如下:
我们定义task变量,并去除ConfigureAwait(false),这样在Calculate中默认会捕获上下文。下面的task.Wait()会等待task完成,可是我们在线程上下文中又会执行Post方法,这时互相等待,造成死锁。解决办法:用到异步的地方都加上ConfigureAwait(false),另一个不要使用Wait方法,用异步就异步到底。
终于讲完了,今天讲的内容还是很简单,如果能帮到你一点点,我就会很开心的(能关注下就更好),哈哈。
最后PS一下这个demo的界面图吧,让你们看看我的设计能力~~
简单理解线程同步上下文相关推荐
- C#学习笔记之线程 - 同步上下文
同步上下文(Synchronization Contexts) 手动使用锁的一个替代方案是去声明锁.通过派生ContextBoundObject和应用Synchronization属性,你告诉CLR自 ...
- 阿里软件测试工程师手把手教学—作为测试,如何理解线程同步异步
案例描述 在日常测试中,当程序加载数据文件时,经常会出现页面卡住.程序不响应.程序崩溃等情况.,调查发现与程序进程中线程的同步和异步有关. 问题描述: 使用文件查看器打开压缩文件时,程序没有响应. 问 ...
- 简单理解:同步、异步、阻塞、非阻塞
同步.异步,是一种协作机制: 同步:发出一次请求后必须等到该请求有返回结果,才能继续下一步工作:请求者需主动询问是否有返回结果: 异步:发出一次请求后无需等到该请求有返回结果,即可进行下一步工作:请求 ...
- 简单的线程同步问题:两个线程交替执行N次【Synchronized、Lock、ArrayBlockingQueue】...
方法一:传统的线程方法import org.apache.log4j.Logger;/*** 两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象.<br/>* 锁是上 ...
- 利用CountDownLatch实现的一个简单的线程同步场景
package countdownlatchTest;import java.util.concurrent.CountDownLatch;class Worker { private String ...
- 同步上下文(SynchronizationContext) 和 C#中跨线程更新UI的方法总结
同步上下文(SynchronizationContext) 和 C#中跨线程更新UI的方法总结 在C#编程环境中,不允许在工作线程中直接对主线程(UI线程)中的控件进行更新操作.因此,稍微复杂一点的程 ...
- 同步上下文(SynchronizationContext)
文章目录 前言 一.简述 1.概念 2.同步上下文的发展 1.原始多线程的环境 2.ISynchronizeInvoke 的诞生 3.SynchronizationContext 的诞生 二.同步上下 ...
- C#线程同步的几种方法
在网上也看过一些关于线程同步的文章,其实线程同步有好几种方法,下面我就简单的做一下归纳. 一.volatile关键字 volatile是最简单的一种同步方法,当然简单是要付出代价的.它只能在变量一级做 ...
- python 测试 多线程 _thread和threading模块 线程同步,线程优先级队列
文章目录 python 多线程简介 Python中使用线程的两种方式 1.函数式 示例 2.线程模块 示例 线程同步 示例 线程优先级队列( Queue)[暂时没用到,没仔细看] 示例 其他 thre ...
最新文章
- WINHEX的数据结构模板
- PyQt5 图片兼容性问题:libpng warning: bKGD: invalid.,原因及解决办法。
- slimphp中间件调用流程的理解
- 群晖linux怎么进入u盘,黑群辉直接更改启动u盘的sn、mac等信息
- [NOIP2015] 子串
- 大大刷新记录!Swin Transformer v2.0 来了,30亿参数!
- 《转》安卓P 刘海屏的适配
- hbase MapReduce程序样例入门
- php中文件上传$_FILES 的错误代码
- Linux虚拟机扩容
- ndimage.median_filter中值滤去除干扰信号
- 笨办法学C 练习31:代码调试
- SpringCloud Alibaba之Nacos组件
- bpsk调制及解调实验_调制的理解
- Xcode5 symbolicatecrash文件路径
- 【Linux】Linux常识28问
- 解决conda install pkgs found conflict问题
- 中国大学MOOC|C语言程序设计(浙江大学翁恺)|习题与解答
- 计算机与人脑的优势与缺点,科学网—《计算机与人脑》笔记 - 王龙飞的博文
- 哈希表构造与处理冲突方法
热门文章
- 关于spring boot多张表建立外健的讨论
- “玩转课堂”基本构想
- 架构师速成4.6-软技能和硬技能
- ElasticSearch远程随意代码运行漏洞(CVE-2014-3120)分析
- Ubuntu16.04换源
- 精通Hibernate:通过Hibernate操纵对象
- poj 2886 Who Gets the Most Candies?(线段树)
- hdu 2648 Shopping
- mysql 中执行的 sql 注意字段之间的反向引号和单引号
- Subversion之路--实现精细的目录访问权限控制(v1.0 更新于2006.12.05)(二)