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

.NET 中的轻量级线程安全

对线程安全有要求的代码中,通常会使用锁(lock)。自 .NET 诞生以来就有锁,然而从 .NET Framework 4.0 开始,又诞生了 6 个轻量级的线程安全方案:SpinLock, SpinWait, CountdownEvent, SemaphoreSlim, ManualResetEventSlim, Barrier


SpinLock, SpinWait

SpinLock 被称之为“自旋锁”,SpinWait 称为“自旋等待”,适合在非常轻量的计算中使用。它与普通 lock 的区别在于普通 lock 使用 Win32 内核态对象来实现等待,Overview of Synchronization Primitives 中描述为:

you can use synchronization primitives that provide fast performance by avoiding expensive reliance on Win32 kernel objects such as wait handles whenever possible.

在这个过程中,调用线程会挂起,并造成线程的上下文切换,而这是一部分不算小的开销。

自旋等待则是继续让 CPU 执行此线程,直到锁释放。在这个过程中,此线程会持续占用 CPU 资源,但避免了线程上下文切换。所以,对于短时间的计算采用 SpinLock 实现线程安全会更加高效;而长时间的任务执行会导致占用 CPU 资源从而导致其他任务执行所需的资源减少。

CountdownEvent

并行执行一些任务之后,通常还会继续执行一些代码。初始化时设置信号量次数,随后在每一个子任务结束之后设置一个信号量(调用其 Signal 方法)可以使计数减 1.这样,在调用 Wait 等待的地方就会等计数为 0 后继续执行。

SemaphoreSlim, ManualResetEventSlim

SemaphoreSlimManualResetEventSlim 是此前 SemaphoreManualResetEvent 的轻量级版本,从其名字“slim”便能看出来。

如何轻量

这些轻量级线程同步方案因为没有使用到 Win32 内核对象,而是在 .NET 内部完成,所以只能进行线程之间的同步,不能进行跨进程同步。如果要完成跨进程的同步,需要使用 MonitorMutex 这样的方案。


参考资料

  • Overview of Synchronization Primitives - Microsoft Docs
  • Thread-Safe Collections - Microsoft Docs
  • .net 4.0新特性-自旋锁(SpinLock) - CSDN博客
  • .net 4.0新特性-CountDownEvent - CSDN博客
  • Atomicity, volatility and immutability are different, part three – Fabulous Adventures In Coding
  • How to: Enable Thread-Tracking Mode in SpinLock - Microsoft Docs
  • C# SpinWait 实现 - 程序园
  • C#并行编程 (Barrier,CountdownEvent,ManualResetEventSlim,SemaphoreSlim,SpinLock,SpinWait )–Thread,Ant,ICP,index,ConsoleWriteLine,CookTasks,cook,particpants

相关文章:

  • 将 WPF、UWP 以及其他各种类型的旧样式的 csproj 文件迁移成新样式的 csproj 文件
  • .NET Core 和 .NET Framework 中的 MEF2
  • 推荐近乎免费的调试神器——OzCode
  • 再也不用克隆多个仓库啦!git worktree 一个 git 仓库可以连接多个工作目录
  • 让一个 csproj 项目指定多个开发框架
  • 在操作系统重启后恢复应用程序的工作状态
  • 生成代码,从 T 到 T1, T2, Tn —— 自动生成多个类型的泛型
  • 应该抛出什么异常?不应该抛出什么异常?(.NET/C#)
  • 关闭模态窗口后,父窗口居然跑到了其他窗口的后面
  • 语义耦合(Semantic Coupling)
  • .NET Core/Framework 创建委托以大幅度提高反射调用的性能
  • 在 Windows 安装期间将 MBR 磁盘转换为 GPT 磁盘
  • 解决大于 4GB 的 Windows 10 镜像在 UEFI 模式下的安装问题
  • 为什么 UEFI 方式启动的 U 盘必须使用 FAT32 文件系统?
  • 不再为命名而苦恼!使用 MSTestEnhancer 单元测试扩展,写契约就够了
  • Cumulo 的 ClojureScript 模块已经成型
  • ERLANG 网工修炼笔记 ---- UDP
  • es6
  • flutter的key在widget list的作用以及必要性
  • JDK 6和JDK 7中的substring()方法
  • JS基础之数据类型、对象、原型、原型链、继承
  • Magento 1.x 中文订单打印乱码
  • Mithril.js 入门介绍
  • MYSQL如何对数据进行自动化升级--以如果某数据表存在并且某字段不存在时则执行更新操作为例...
  • Promise面试题,控制异步流程
  • Python socket服务器端、客户端传送信息
  • vue总结
  • 多线程 start 和 run 方法到底有什么区别?
  • 学习ES6 变量的解构赋值
  • 一起来学SpringBoot | 第十篇:使用Spring Cache集成Redis
  • 阿里云IoT边缘计算助力企业零改造实现远程运维 ...
  • ​虚拟化系列介绍(十)
  • #Z2294. 打印树的直径
  • (1)bark-ml
  • (NO.00004)iOS实现打砖块游戏(十二):伸缩自如,我是如意金箍棒(上)!
  • (搬运以学习)flask 上下文的实现
  • (办公)springboot配置aop处理请求.
  • (附源码)springboot 房产中介系统 毕业设计 312341
  • (附源码)springboot炼糖厂地磅全自动控制系统 毕业设计 341357
  • (牛客腾讯思维编程题)编码编码分组打印下标题目分析
  • (原創) 系統分析和系統設計有什麼差別? (OO)
  • (转)Mysql的优化设置
  • (转)Spring4.2.5+Hibernate4.3.11+Struts1.3.8集成方案一
  • ./configure,make,make install的作用
  • .bashrc在哪里,alias妙用
  • .net core使用RPC方式进行高效的HTTP服务访问
  • .NET处理HTTP请求
  • .NET高级面试指南专题十一【 设计模式介绍,为什么要用设计模式】
  • .NET开发人员必知的八个网站
  • .NET企业级应用架构设计系列之技术选型
  • @DateTimeFormat 和 @JsonFormat 注解详解
  • @Validated和@Valid校验参数区别
  • [ C++ ] STL_vector -- 迭代器失效问题
  • [Angular 基础] - 表单:响应式表单
  • [Angularjs]asp.net mvc+angularjs+web api单页应用之CRUD操作