您是否曾花费几个小时试图调试多线程应用程序中出现的非确定性问题?如果是这样,那么你一定要阅读这篇文章。如果不是,那么它无论如何都是修改您当前关于C#中的线程挑战的知识的好方法。了解有关线程的一些常见事实可以帮助您在将来构建设计良好,防错误的多线程应用程序。

如果线程具有对同一对象实例的公共引用,则它们共享数据

代码如下:

执行时,结果为:在屏幕上打印Work done。正如您在上面的示例中所看到的,两个线程(main和newThread)都在SomeClass的同一个实例上调用DoWork()方法。因此,虽然_isWorkDone字段是非静态的,但它们共享它。因此,"Work done"仅在屏幕上打印一次,而不知道上述内容的程序员则希望打印两次。

当进程终止时,不执行后台线程中的"finally"块

代码如下:

执行时,结果为:Doing some work......Closing the program...打印在屏幕上。正如您在上面的示例中所看到的,当进程终止时(因为主线程已完成其执行),后台线程中的"finally"块不会被执行。如果在最后完成"处理"工作,例如关闭流,释放资源或删除一些临时文件,这可能会造成很大的麻烦。

Lambda表达式中的捕获值也是共享的

代码如下:

应该导致以下输出:0123456789嗯,它没有。结果是完全不确定的!这里的技巧是i变量在"for"循环的整个生命周期中引用相同的内存位置。因此,每个线程在同一个变量上调用Console.Write方法,该变量在运行时发生变化。上面的解决方案是使用临时变量:

锁定不会以任何方式限制对同步对象本身的访问。

这意味着,如果一个线程调用:lock(x)而另一个线程调用x.ToString(),则后者不会被阻塞。换句话说:用于锁定的物体是未被锁定的储物柜。

创建线程时在范围内尝试/ catch / finally块,在线程开始执行时与线程无关

代码如下:

不会导致在Main方法的"catch"块中捕获异常。遗憾的是,它仍未被捕,将导致程序关闭。解决上述问题最自然的方法当然是将try / catch块移动到Divide方法。

如果一个对象是线程安全的,那并不意味着你不需要锁定它来访问它

代码如下:

假设_list类完全是线程安全的。然而,在检查和添加到列表之间仍有可能另一个线程已经添加了某个项目。上面的例子表明,拥有一个线程安全的类并不意味着当你使用它时代码仍然是线程安全的。

程序的指令可以由编译器,CLR或CPU重新排序,以提高效率。

对于那些不了解这一点的开发人员来说,这可能真的很棘手。为了解释这个过程,我们首先来看看下面这段代码:

问题是:这是可能的,假设A和B在不同的线程上同时运行,B将在屏幕上写"0"吗?逻辑上认为不是:在_done设置为true之前,我们无法进入Console.WriteLine。要将_done设置为true,我们首先需要为_value字段分配1。令人惊讶的是,尽管有可能,因为:

· 编译器,CLR或CPU可能会重新排序程序的指令以提高其效率.

· 编译器,CLR或CPU可能会引入缓存优化,这样对变量的赋值将立即对其他线程不可见.

好的,现在问题出现了:如何解决这样的挑战?那么至少有一些解决方案,但通常最优选的解决方案是创建内存栅栏。简而言之,完整的内存屏障(围栏)在使用时可防止任何类型的指令重新排序或缓存此屏障。在C#中,您调用Thread.Barrier来生成这样的围栏。在上面的示例中,以下代码将解决我们的问题:

如果您想了解更多关于构建多线程应用程序时可能遇到的不同挑战和问题,我强烈推荐Joseph Albahari的免费电子书 :C#中的线程。 如果您了解C#中与线程相关的其他一些有趣场景,请随时通过发表评论与我们分享!

insert时调用本身字段_多线程编程时,7件你必须知道的事情相关推荐

  1. insert时调用本身字段_「技术篇」ETL工具Kettle数据对比同步以及Java程序中调用

    作为一个技术栈出身的攻城狮,虽然走上管理之路,但是技术是不能扔下的,时不时的拿起来重温一下,理论与实践相结合... 使用背景: 住建部某区块链共享平台(下游系统)需要自于上游系统的生产库数据,数据量不 ...

  2. insert时调用本身字段_MySQL RC级别下并发insert锁超时问题 - 案例验证

    作者:网易数据库团队 DDB(网易杭研自研的MySQL数据库中间件产品)团队小伙伴发现了一个问题,觉得比较奇怪.于是找到我们,希望解释下.过程中除解释了问题的现象,也通过代码了解了更多的InnoDB ...

  3. insert时调用本身字段_python3调用企业微信api!开发一款属于自己的企业微信

    python3调用企业微信api 最后更新时间:2020/5/11 前段时间,我将企业微信官方提供的python接口代码的部分功能修改成了python3的,并且自己也使用并测试过部分功能: 因为并没有 ...

  4. insert时调用本身字段_java中子类调用父类构造方法注意事项

    protected继承 继承有个特点,就是子类无法访问父类的private字段或者private方法.例如,Student类就无法访问Person类的name和age字段: class Person ...

  5. 多线程 转账_多线程编程不可错过——彻底理解volatile

    持续分享互联网一线研发技术,欢迎关注我. volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Ja ...

  6. java图形界面多线程_多线程编程、Java I/O系统和Java图形界面编程

    多线程编程: 一个正在运行的程序通常称为一个进程,每一个任务称为一个线程,中能够在一个程序内运行多线程的程序称为多线程程序. 线程与进程的区别:①每个进程都需要操作系统为其分配独立的内存空间: ②而同 ...

  7. Linux开发_多线程编程

    Linux下的多线程使用的库是pthread,是一个遵守POSIX接口的函数库. Linux下多线程编程对函数定义原型有要求,必须是void *函数名(void *参数名),或者void 函数名(vo ...

  8. java integer 不变模式_多线程编程的设计模式 不变模式(zt)

    因为字符串类是不变模式最典型的代表,所以其它的知识将在下面继续介绍. 多线程编程的设计模式 不变模式(二) 不变模式(Immutable Pattern)顾名思义,它的状态在它的生命周期内是永恒的(晕 ...

  9. 自旋锁和互斥锁实例_多线程编程之自旋锁

    一.什么是自旋锁 一直以为自旋锁也是用于多线程互斥的一种锁,原来不是! 自旋锁是专为防止多处理器并发(实现保护共享资源)而引入的一种锁机制.自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用 ...

最新文章

  1. js正则验证特殊字符
  2. memcached缓存失效时的高并发访问问题解决
  3. Spring 极速集成注解 Redis 实践
  4. jpa query 取数组第一个_数据结构基础-数组
  5. 一个项目经理的一些个人体会
  6. COM、COM+和DCOM的定义和区别
  7. C# 连接Access数据库
  8. 在LUA中使用异步IO的思考
  9. 施努卡:什么是视觉定位系统 视觉系统如何定位
  10. element-ui局部区域loading效果
  11. mysql 免安装 net_mysql 免安装
  12. 如何拯救拖延症??11大招总有一招帮你搞定
  13. html顺势正旋转360度,庞明:混元太极揉球
  14. LPC1768 SPI 外设控制DA(PCM1796)调试记录
  15. java开发购物系统菜单_Java控制台购物系统
  16. ftp 下载 工具,5款小白都能使用的ftp 下载 工具
  17. 第一章、华软代码生成器简单模板调制教程
  18. python日志审计系统_综合日志审计系统
  19. 批发供应系统批发订货发货管理系统开发功能
  20. c语言apply函数,R语言apply()函数用法(示例代码)

热门文章

  1. 2019一级计算机等级考试试题,2019年全国计算机等级考试一级练习试题及答案(一)...
  2. .net 延时操作_锁、CAS操作和无锁队列的实现
  3. mysql 时间点_mysql 时间
  4. Spring Boot整合Swagger3注解@ApiImplicitParam的allowMultiple属性
  5. 正则提取Swagger在线文档里面的返回实体类字段
  6. 一支python教学_第一只python爬虫
  7. JAVA高性能内存队列-disruptor
  8. 生产者消费者模式-java原生、Disruptor实现方案
  9. 连接Oracle时报错ORA-28547
  10. 已知一个点的经纬度、方位角、距离,求另一点经纬度