0

0

c# 在并发编程中,无锁和有锁算法的权衡

幻夢星雲

幻夢星雲

发布时间:2026-01-08 10:03:08

|

809人浏览过

|

来源于php中文网

原创

无锁算法在C#中并非完全不加锁,而是不使用lock等阻塞原语,依赖Interlocked和CAS实现线程安全;线程不挂起但可能自旋耗CPU,适用于高频简单操作,复杂逻辑或协同更新应优先用lock。

c# 在并发编程中,无锁和有锁算法的权衡

无锁算法在 C# 中真的不加锁吗?

“无锁”不是字面意义的完全不用锁,而是指不依赖 lockMutexMonitor 这类阻塞式同步原语;它靠 Interlocked 系列方法(如 Interlocked.CompareExchange)和 CPU 提供的原子指令(CAS)实现线程安全。关键在于:线程不会因竞争而挂起,但可能自旋重试——这会吃 CPU,尤其在高争用时。

  • 典型场景:高频读写计数器、单生产者单消费者队列、对象池的轻量级分配
  • 常见误判:把 volatile 当成线程安全手段——它只保证可见性,不保证原子性或顺序性
  • 风险点:Interlocked 仅支持基础类型(intlongref 等),无法直接用于复杂对象状态更新

C# 中哪些并发集合默认用了无锁?

ConcurrentQueueConcurrentStackConcurrentBag 在 .NET Core 2.1+ 及 .NET 5+ 中大量使用无锁策略(尤其是前两者底层基于 Interlocked + 分段数组),但不是“纯无锁”:它们在扩容、边界处理等少数路径仍会退化到细粒度锁(如 SpinLock 或内部 lock)。

  • 不要假设“Concurrent”前缀 = 全程无锁;查看源码可知 ConcurrentDictionary 内部用分段锁(locks[] 数组),属于有锁优化而非无锁
  • 性能拐点明显:当线程数远超 CPU 核心数,或单个操作耗时变长(如含 I/O 或复杂计算),无锁自旋开销会迅速压倒收益
  • 调试困难:无锁逻辑出错往往表现为偶发数据丢失或无限循环,堆里看不到阻塞点,难复现

什么时候该主动放弃无锁,改用 lock?

当你需要保护一段**非原子的多步逻辑**,或者涉及**多个共享变量的协同更新**,硬套无锁极易出错。例如:检查一个条件后再修改两个字段,CAS 无法一步完成这种“检查-执行”事务。

Med-PaLM
Med-PaLM

来自 Google Research 的大型语言模型,专为医学领域设计。

下载
  • 典型信号:你开始写嵌套的 while (true) + CompareExchange 循环,并在里面做条件判断和分支赋值——这已偏离无锁初衷,且极易漏掉 ABA 问题
  • 更稳妥的选择:lock 虽然阻塞,但在争用不激烈(如每秒几十次操作)、临界区极短(
  • 注意 lock 对象粒度:避免锁住 thistypeof(MyClass),优先用私有 readonly object _sync = new();
private readonly object _sync = new();
private int _value;
private string _status;

// ✅ 推荐:用 lock 保护多字段协同更新 public void UpdateValueAndStatus(int newValue, string newStatus) { lock (_sync) { _value = newValue; _status = newStatus; // 还可能触发事件、更新缓存……这些无法用单一 CAS 表达 } }

// ❌ 避免:试图用 Interlocked 拆解多步逻辑(错误且不可靠) public void BadAttemptToUpdate() { while (true) { var oldVal = _value; var newVal = oldVal + 1; if (Interlocked.CompareExchange(ref _value, newVal, oldVal) == oldVal) { // 此时 _status 可能已被其他线程改写,状态不一致 _status = "updated"; // 这行不是原子的! break; } } }

无锁的真正门槛不在代码长度,而在对内存模型、CPU 缓存一致性协议(如 MESI)和 ABA 本质的理解。多数业务场景下,先用 Concurrent* 集合或 lock,压测发现瓶颈后再针对性替换为无锁实现——过早优化无锁,八成是在给自己埋坑。

相关文章

编程速学教程(入门课程)
编程速学教程(入门课程)

编程怎么学习?编程怎么入门?编程在哪学?编程怎么学才快?不用担心,这里为大家提供了编程速学教程(入门课程),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

83

2023.09.25

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

315

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

529

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

50

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

193

2025.08.29

c++中volatile关键字的作用
c++中volatile关键字的作用

本专题整合了c++中volatile关键字的相关内容,阅读专题下面的文章了解更多详细内容。

67

2025.10.23

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

382

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

567

2023.08.10

Golang 分布式缓存与高可用架构
Golang 分布式缓存与高可用架构

本专题系统讲解 Golang 在分布式缓存与高可用系统中的应用,涵盖缓存设计原理、Redis/Etcd集成、数据一致性与过期策略、分布式锁、缓存穿透/雪崩/击穿解决方案,以及高可用架构设计。通过实战案例,帮助开发者掌握 如何使用 Go 构建稳定、高性能的分布式缓存系统,提升大型系统的响应速度与可靠性。

6

2026.01.09

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 1.0万人学习

进程与SOCKET
进程与SOCKET

共6课时 | 0.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号