0

0

c# C#中的原子操作 Interlocked类详解

煙雲

煙雲

发布时间:2026-01-19 13:53:02

|

567人浏览过

|

来源于php中文网

原创

interlocked 不能直接操作普通变量,因其所有方法均要求 ref 参数以确保作用于同一内存地址,依赖 cpu 原子指令;compareexchange 是唯一支持 cas 的方法,适用于数值与引用类型;read/ add/increment 在 x86 上对 long 需 lock 指令保证原子性,而 int 始终原子;.net 6+ 泛型 compareexchange 仅安全支持不可变引用类型或纯值类型。

c# c#中的原子操作 interlocked类详解

Interlocked 为什么不能直接操作普通变量

因为 Interlocked 的所有方法都要求传入 ref intref long 等引用类型参数,它底层依赖 CPU 的原子指令(如 x86 的 XCHGLOCK XADD),这些指令必须作用在内存地址上。如果你传一个局部值类型变量(比如 int i = 0;),编译器会报错:「无法将“int”类型的值作为 ref 参数传递」——这不是语法限制,而是语义强制:必须确保操作的是同一块可寻址内存。

常见错误写法:

int value = 42;
int result = Interlocked.Add(value, 1); // ❌ 编译失败:期望 ref int

正确做法是始终用 ref 传变量地址:

int value = 42;
int result = Interlocked.Add(ref value, 1); // ✅

CompareExchange 是唯一能做“CAS”的方法

Interlocked.CompareExchange 是 C# 中实现无锁编程的核心,它完成「比较并交换」:仅当当前值等于预期值时,才把新值写入,并返回原始值。它不像 AddIncrement 那样只适用于数值,还能用于引用类型(object、自定义类等)和泛型版本(.NET 6+)。

典型使用场景:

  • 实现线程安全的单例懒加载(不用 lock
  • 构建无锁 / 队列的节点链接逻辑
  • 避免重复初始化共享资源

示例:用 CAS 实现简易计数器初始化

private static int _counter = 0;
private static readonly object _initLock = new();
<p>public static int GetCounter()
{
if (_counter == 0)
{
// 可能多个线程同时进这里,只让一个成功写入
Interlocked.CompareExchange(ref _counter, 1, 0);
}
return _counter;
}

注意:上面例子中,CompareExchange 返回的是交换前的值,所以你得靠返回值判断是否真正执行了赋值,而不是只看条件 _counter == 0 —— 因为判断和交换之间存在竞态窗口。

Read、Add、Increment 在 32/64 位平台上的行为差异

Interlocked.Read 是个特例:它只接受 ref long,且在 x64 上被编译为单条 MOV 指令,在 x86 上则必须用 LOCK MOV(实际是 LOCK XCHG)来保证 64 位读取的原子性。而 Interlocked.Add(ref long, long)Interlocked.Increment(ref long) 在 x86 上同样依赖 LOCK 前缀指令,性能开销略高于 32 位操作。

问小白
问小白

免费使用DeepSeek满血版

下载

关键事实:

  • int 类型的 Interlocked 操作在所有平台都是原子的,无需额外同步
  • long 在 x86 上不是自然原子的,必须走 Interlocked,不能直接读/写字段
  • Interlocked.Read(ref long) 是唯一安全读取未对齐或并发更新的 long 字段的方式

错误示范(x86 下可能读到撕裂值):

private long _timestamp;
public long GetTimestamp() => _timestamp; // ❌ 可能返回高低 32 位来自不同写入的结果

正确写法:

private long _timestamp;
public long GetTimestamp() => Interlocked.Read(ref _timestamp); // ✅

泛型 CompareExchange 在 .NET 6+ 中的适用边界

.NET 6 引入了 Interlocked.CompareExchange<t>(ref T, T, T)</t>,但它有硬性约束:类型 T 必须是「不可变的引用类型」或「由编译器保证按位可比的值类型」,实际上目前只安全支持 classstruct(且不含引用字段)、以及 IntPtrUIntPtr 等少数类型。你不能对含字符串字段或 List 的类实例做泛型 CAS —— 编译器会允许,但运行时行为未定义。

更隐蔽的问题是内存模型:泛型版本不保证对字段的重新排序屏蔽,所以在复杂对象状态切换中,仍需配合 Volatile.Read/Volatile.WriteMemoryBarrier 使用。

推荐优先级:

  • 简单标志位 → 用 int + CompareExchange(ref int, 1, 0)
  • 对象引用替换 → 用泛型版,但确保 T 是纯数据容器(如 State struct)
  • 含副作用的状态机 → 别硬套 Interlocked,改用 lockSpinLock

真正难的从来不是调哪个方法,而是判断「这个变量的修改是否需要和其他字段的修改保持顺序一致」——这时候 Interlocked 自身解决不了,得看整个同步契约。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

718

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

219

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1561

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

647

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

1148

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

1122

2024.04.29

go语言字符串相关教程
go语言字符串相关教程

本专题整合了go语言字符串相关教程,阅读专题下面的文章了解更多详细内容。

188

2025.07.29

c++字符串相关教程
c++字符串相关教程

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

111

2025.08.07

Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

4

2026.03.05

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
nginx浅谈
nginx浅谈

共15课时 | 0.9万人学习

前端开发(基础+实战项目合集)
前端开发(基础+实战项目合集)

共60课时 | 4.3万人学习

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

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