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

为什么实现 .NET 的 ICollection 集合时需要实现 SyncRoot 属性?如何正确实现这个属性?

非泛型版本的 ICollection 中有 IsSynchronized 属性和 SyncRoot 属性,这两个属性被用来设计成以线程安全的方式访问和修改集合。不过这个设计让线程安全的访问由集合的实现方转嫁到了调用方,导致要么很难实现,要么很难调用。

虽然泛型版本的 ICollection<T> 已经改进了设计,不再引入 SyncRoot 这样的属性到接口中,但如果我们在某些场景下需要实现 ICollection 非泛型集合时,如何正确实现 SyncRoot 模式(SyncRoot Pattern)呢?


先上结论:

—— 不可能正确实现 SyncRoot 模式

在多线程程序设计中,为了在保证线程安全的同时避免死锁,不应该公开同步锁。而 ICollection 接口中的 SyncRoot 属性在接口中必然是公开的,于是没有任何途径可以保证调用方不会发生死锁。

于是实现 SyncRoot 的正确方法应该是:

—— 避免公开 SyncRoot 属性

所以 SyncRoot 模式应该这样实现:

  1. 使用显式接口实现,避免公开暴露此属性
  2. 抛出异常,避免调用者使用此属性

结合 .NET Core 源代码中的一些常用写法,我给出一个推荐的 SyncRoot 模式的写法:

// Is this List synchronized (thread-safe)?
bool ICollection.IsSynchronized => false;

// Synchronization root for this object.
object ICollection.SyncRoot => this;

嗯,没错,返回了 this,这是各种同步时绝对不应该使用的对象。然而这个属性都是 public 了,不管返回什么,与 this 还有什么区别……

关于为什么同步时不应该返回 this 或者返回公开的对象,原因可以看我的另一篇博客:

  • 为什么不应该公开用来同步的加锁对象?为什么不应该 lock(this)/lock(string) 或者 lock 任何非私有对象? - walterlv

我的博客会首发于 https://blog.walterlv.com/,而 CSDN 会从其中精选发布,但是一旦发布了就很少更新。

如果在博客看到有任何不懂的内容,欢迎交流。我搭建了 dotnet 职业技术学院 欢迎大家加入。

知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://walterlv.blog.csdn.net/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。

相关文章:

  • 为什么不应该公开用来同步的加锁对象?为什么不应该 lock(this)/lock(string) 或者 lock 任何非私有对象?
  • WPF 中如何创建忽略 DPI 属性的图片
  • .NET 中选择合适的文件打开模式(CreateNew, Create, Open, OpenOrCreate, Truncate, Append)
  • Win32 方法 CreateFile 中选择合适的文件打开模式(CREATE_NEW, CREATE_ALWAYS, OPEN_EXISTING, OPEN_ALWAYS, TRUNCATE_EXI
  • 使用 Kestrel 为你的 ASP.NET Core 服务添加 https 支持
  • 三种方法为 ASP.NET Core 对外服务添加 https 支持(kestrel / frp / nginx)
  • 为 ASP.NET Core 程序制作 URL 的 301/302 跳转
  • 使用 Frp 为你的 Web 服务添加 https 支持
  • 全民 https!使用 FreeSSL 申请免费的 https 证书
  • 如何设置 ASP.NET Core 程序监听的 IP 和端口
  • 收集的 Linux VPS 在线重装系统脚本
  • Linux 系统根目录下的文件夹
  • 修复 Windows 10 设置界面里面混乱的语言翻译
  • .NET 程序如何获取图片的宽高(框架自带多种方法的不同性能)
  • 用命令行执行 .NET 单元测试时,如何仅执行符合某些条件的单元测试
  • 【5+】跨webview多页面 触发事件(二)
  • Android组件 - 收藏集 - 掘金
  • docker容器内的网络抓包
  • ERLANG 网工修炼笔记 ---- UDP
  • export和import的用法总结
  • oschina
  • seaborn 安装成功 + ImportError: DLL load failed: 找不到指定的模块 问题解决
  • sessionStorage和localStorage
  • SOFAMosn配置模型
  • tensorflow学习笔记3——MNIST应用篇
  • webpack项目中使用grunt监听文件变动自动打包编译
  • 从0搭建SpringBoot的HelloWorld -- Java版本
  • 浮现式设计
  • 解析 Webpack中import、require、按需加载的执行过程
  • 使用iElevator.js模拟segmentfault的文章标题导航
  • 微信小程序--------语音识别(前端自己也能玩)
  • 新手搭建网站的主要流程
  • 一些基于React、Vue、Node.js、MongoDB技术栈的实践项目
  • linux 淘宝开源监控工具tsar
  • Redis4.x新特性 -- 萌萌的MEMORY DOCTOR
  • shell使用lftp连接ftp和sftp,并可以指定私钥
  • 带你开发类似Pokemon Go的AR游戏
  • !$boo在php中什么意思,php前戏
  • ###C语言程序设计-----C语言学习(3)#
  • #Java第九次作业--输入输出流和文件操作
  • #pragma multi_compile #pragma shader_feature
  • (14)目标检测_SSD训练代码基于pytorch搭建代码
  • (3)Dubbo启动时qos-server can not bind localhost22222错误解决
  • (分布式缓存)Redis哨兵
  • (十八)三元表达式和列表解析
  • (原創) 如何解决make kernel时『clock skew detected』的warning? (OS) (Linux)
  • (转)LINQ之路
  • (转)德国人的记事本
  • *1 计算机基础和操作系统基础及几大协议
  • .NET 4.0网络开发入门之旅-- 我在“网” 中央(下)
  • .NET CF命令行调试器MDbg入门(二) 设备模拟器
  • .NET中的十进制浮点类型,徐汇区网站设计
  • [.net 面向对象程序设计进阶] (19) 异步(Asynchronous) 使用异步创建快速响应和可伸缩性的应用程序...
  • [20150707]外部表与rowid.txt
  • [202209]mysql8.0 双主集群搭建 亲测可用