为了线程安全,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的界面图吧,让你们看看我的设计能力~~

简单理解线程同步上下文相关推荐

  1. C#学习笔记之线程 - 同步上下文

    同步上下文(Synchronization Contexts) 手动使用锁的一个替代方案是去声明锁.通过派生ContextBoundObject和应用Synchronization属性,你告诉CLR自 ...

  2. 阿里软件测试工程师手把手教学—作为测试,如何理解线程同步异步

    案例描述 在日常测试中,当程序加载数据文件时,经常会出现页面卡住.程序不响应.程序崩溃等情况.,调查发现与程序进程中线程的同步和异步有关. 问题描述: 使用文件查看器打开压缩文件时,程序没有响应. 问 ...

  3. 简单理解:同步、异步、阻塞、非阻塞

    同步.异步,是一种协作机制: 同步:发出一次请求后必须等到该请求有返回结果,才能继续下一步工作:请求者需主动询问是否有返回结果: 异步:发出一次请求后无需等到该请求有返回结果,即可进行下一步工作:请求 ...

  4. 简单的线程同步问题:两个线程交替执行N次【Synchronized、Lock、ArrayBlockingQueue】...

    方法一:传统的线程方法import org.apache.log4j.Logger;/*** 两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象.<br/>* 锁是上 ...

  5. 利用CountDownLatch实现的一个简单的线程同步场景

    package countdownlatchTest;import java.util.concurrent.CountDownLatch;class Worker { private String ...

  6. 同步上下文(SynchronizationContext) 和 C#中跨线程更新UI的方法总结

    同步上下文(SynchronizationContext) 和 C#中跨线程更新UI的方法总结 在C#编程环境中,不允许在工作线程中直接对主线程(UI线程)中的控件进行更新操作.因此,稍微复杂一点的程 ...

  7. 同步上下文(SynchronizationContext)

    文章目录 前言 一.简述 1.概念 2.同步上下文的发展 1.原始多线程的环境 2.ISynchronizeInvoke 的诞生 3.SynchronizationContext 的诞生 二.同步上下 ...

  8. C#线程同步的几种方法

    在网上也看过一些关于线程同步的文章,其实线程同步有好几种方法,下面我就简单的做一下归纳. 一.volatile关键字 volatile是最简单的一种同步方法,当然简单是要付出代价的.它只能在变量一级做 ...

  9. python 测试 多线程 _thread和threading模块 线程同步,线程优先级队列

    文章目录 python 多线程简介 Python中使用线程的两种方式 1.函数式 示例 2.线程模块 示例 线程同步 示例 线程优先级队列( Queue)[暂时没用到,没仔细看] 示例 其他 thre ...

最新文章

  1. WINHEX的数据结构模板
  2. PyQt5 图片兼容性问题:libpng warning: bKGD: invalid.,原因及解决办法。
  3. slimphp中间件调用流程的理解
  4. 群晖linux怎么进入u盘,黑群辉直接更改启动u盘的sn、mac等信息
  5. [NOIP2015] 子串
  6. 大大刷新记录!Swin Transformer v2.0 来了,30亿参数!
  7. 《转》安卓P 刘海屏的适配
  8. hbase MapReduce程序样例入门
  9. php中文件上传$_FILES 的错误代码
  10. Linux虚拟机扩容
  11. ndimage.median_filter中值滤去除干扰信号
  12. 笨办法学C 练习31:代码调试
  13. SpringCloud Alibaba之Nacos组件
  14. bpsk调制及解调实验_调制的理解
  15. Xcode5 symbolicatecrash文件路径
  16. 【Linux】Linux常识28问
  17. 解决conda install pkgs found conflict问题
  18. 中国大学MOOC|C语言程序设计(浙江大学翁恺)|习题与解答
  19. 计算机与人脑的优势与缺点,科学网—《计算机与人脑》笔记 - 王龙飞的博文
  20. 哈希表构造与处理冲突方法

热门文章

  1. 关于spring boot多张表建立外健的讨论
  2. “玩转课堂”基本构想
  3. 架构师速成4.6-软技能和硬技能
  4. ElasticSearch远程随意代码运行漏洞(CVE-2014-3120)分析
  5. Ubuntu16.04换源
  6. 精通Hibernate:通过Hibernate操纵对象
  7. poj 2886 Who Gets the Most Candies?(线段树)
  8. hdu 2648 Shopping
  9. mysql 中执行的 sql 注意字段之间的反向引号和单引号
  10. Subversion之路--实现精细的目录访问权限控制(v1.0 更新于2006.12.05)(二)