当前位置: 首页 > news >正文

C#线程同步

c#线程同步代码示例

仔细考虑下面这段代码是不是输出0

    const int _max = 1000000;private int _count = 0;void Start(){Task task = Task.Run(() =>{Decr();});for (int i = 0; i < _max; i++){_count++;}task.Wait();Debug.Log(_count);}void Decr(){for(int i = 0; i < _max; i++){_count--;}}

下面这个代码呢

const int _max = 1000000;private int _count = 0;object _sync = new object();void Start(){Task task = Task.Run(() =>{Decr();});for (int i = 0; i < _max; i++){lock (_sync){_count++;   }}task.Wait();Debug.Log(_count);}void Decr(){for(int i = 0; i < _max; i++){lock (_sync){_count--;   }}

将要访问_Count的代码段锁定了之后(用lock)​,Main()和Decr()方法就是线程安全的。换言之,可从多个线程中同时安全地调用它们

即使为了同步的需要可以忍受lock的速度,也不要在多处理器计算机中不假思索地添加同步来避免死锁和不必要的同步(也许本来可以并行执行的)​。

object 必须是引用类型的对象。如果你尝试将一个值类型(如结构体或基本数据类型如 int)作为 lock 语句的参数,编译器会报错。例如:

int myLock = 0;
lock (myLock) // 编译错误:不能将值类型作为 lock 的参数
{// 代码
}

这会导致编译错误,因为 myLock 是一个 int,它是一个值类型。正确的做法是使用一个引用类型的对象作为锁

为什么要避免锁定this、typeof(type)和string

一个貌似合理的模式是锁定代表类中实例数据的this关键字,以及为静态数据锁定从typeof(type)(例如typeof(MyType))获取的类型实例。在这种模式下,使用this可为与特定对象实例关联的所有状态提供同步目标;使用typeof(type)则为一个类型的所有静态数据提供同步目标。但这样做的问题在于,在另一个完全不相干的代码块中,可能创建一个完全不同的同步块,而这个同步块的同步目标可能就是this(或typeof(type))所指向的同步目标。换言之,虽然只有实例自身内部的代码能用this关键字来阻塞,但创建实例的调用者仍可将那个实例传给一个同步锁。

简单来说  经常锁定this,调用者无意间可能也把这个对象当作锁,有死锁的隐患

要避免的另一个锁定类型是string,这是因为要考虑到字符串留用问题。如同一个字符串常量在多个位置出现,那么所有位置都可能引用同一个实例,使锁定的范围大于预期

将字段声明为volatile

编译器和/或CPU有时会对代码进行优化,使指令不按照它们的编码顺序执行,或干脆拿掉一些无用指令。若代码只在一个线程上执行,像这样的优化无伤大雅。但对于多个线程,这种优化就可能造成出乎预料的结果,因为优化可能造成两个线程对同一字段的读写顺序发生错乱。

解决该问题的一个方案是用volatile关键字声明字段。该关键字强迫对volatile

字段的所有读写操作都在代码指示的位置发生,而不是在通过优化而生成的其他某个位置发生。volatile修饰符指出字段容易被硬件、操作系统或另一个线程修改。所以这种数据是“易变的”​(volatile)​,编译器和“运行时”要更严谨地处理它。

一般很少使用volatile修饰符。即便使用,也可能因为疏忽而使用不当。lock比volatile更好,除非对volatile的用法有绝对的把握。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 大众(奥迪)汽车继电器编号对照表
  • uniapp+vue3实现双通道透明MP4播放支持小程序和h5
  • sicp每日一题[1.45]
  • LeetCode 热题100-17 缺失的第一个正数
  • nodejs笔记
  • 聚观早报 | 淘宝将支持微信支付;董明珠支持招35岁员工
  • AE调试一些记录(1)
  • 探索NVIDIA RTX 4060 8G与RTX 3060 12G:性能与适用场景的深度解析
  • 从零开始,认识游戏设计师(3)体验源于设计师①
  • 苹果手机怎么设置铃声?3个方法教你制定个性化铃声
  • 鲁大师8月新机性能/流畅/AI/久用榜:新机节奏放缓,但不乏小惊喜
  • Linux malloc内存分配实现原理
  • 828华为云征文 | Flexus X实例与Harbor私有镜像仓库的完美结合
  • armbian cups 远程打印机 1022
  • 「OC」iOS事件处理流程
  • 【译】JS基础算法脚本:字符串结尾
  • 30天自制操作系统-2
  • Create React App 使用
  • el-input获取焦点 input输入框为空时高亮 el-input值非法时
  • Java 9 被无情抛弃,Java 8 直接升级到 Java 10!!
  • mysql 数据库四种事务隔离级别
  • Mysql数据库的条件查询语句
  • overflow: hidden IE7无效
  • Vue2.0 实现互斥
  • VuePress 静态网站生成
  • 从0到1:PostCSS 插件开发最佳实践
  • 动态规划入门(以爬楼梯为例)
  • 机器学习中为什么要做归一化normalization
  • 今年的LC3大会没了?
  • 前端学习笔记之观察者模式
  • 使用common-codec进行md5加密
  • 使用Maven插件构建SpringBoot项目,生成Docker镜像push到DockerHub上
  • -- 数据结构 顺序表 --Java
  • 听说你叫Java(二)–Servlet请求
  • 我的面试准备过程--容器(更新中)
  • 小程序上传图片到七牛云(支持多张上传,预览,删除)
  • 转载:[译] 内容加速黑科技趣谈
  • Hibernate主键生成策略及选择
  • ​第20课 在Android Native开发中加入新的C++类
  • ​批处理文件中的errorlevel用法
  • (4)通过调用hadoop的java api实现本地文件上传到hadoop文件系统上
  • (汇总)os模块以及shutil模块对文件的操作
  • (转)http协议
  • (转)LINQ之路
  • (转)Sql Server 保留几位小数的两种做法
  • (转)淘淘商城系列——使用Spring来管理Redis单机版和集群版
  • *ST京蓝入股力合节能 着力绿色智慧城市服务
  • .bat批处理(十一):替换字符串中包含百分号%的子串
  • .equals()到底是什么意思?
  • .Net 6.0--通用帮助类--FileHelper
  • .NET CORE 第一节 创建基本的 asp.net core
  • .net core 连接数据库,通过数据库生成Modell
  • .net 按比例显示图片的缩略图
  • .Net 中Partitioner static与dynamic的性能对比
  • .NET 中各种混淆(Obfuscation)的含义、原理、实际效果和不同级别的差异(使用 SmartAssembly)