以下是 C# 中使用 int
类型结合 Interlocked
类实现原子操作的完整示例,涵盖状态切换、计数控制等常见场景:
完整代码示例csharp
using System;
using System.Threading;/// <summary>
/// 基于整数类型的原子操作工具类(线程安全)
/// 适用于开关状态控制、计数器等场景
/// </summary>
public static class AtomicStateManager
{// 核心状态变量:用整数表示不同状态// 示例场景:0=关闭(False),1=开启(True);也可扩展为多状态(如0=未初始化,1=运行中,2=已停止)private static int _state = 0; #region 基础状态控制(开关场景)/// <summary>/// 原子设置状态为“开启”(对应值1)/// </summary>public static void Enable(){// 直接将状态设为1,无视当前值(原子操作)Interlocked.Exchange(ref _state, 1);}/// <summary>/// 原子设置状态为“关闭”(对应值0)/// </summary>public static void Disable(){// 直接将状态设为0,无视当前值(原子操作)Interlocked.Exchange(ref _state, 0);}/// <summary>/// 原子切换状态(0→1 或 1→0)/// </summary>public static void Toggle(){// 循环尝试切换,直到成功(处理并发冲突)do{int currentState = _state; // 读取当前状态int newState = currentState == 1 ? 0 : 1; // 计算目标状态// 比较并交换:如果当前值仍为currentState,则更新为newState// 若交换失败(返回值≠currentState),则重试} while (Interlocked.CompareExchange(ref _state, newState, _state) != _state);}/// <summary>/// 原子读取当前状态是否为“开启”/// </summary>/// <returns>True=开启(1),False=关闭(0)</returns>public static bool IsEnabled(){// 用CompareExchange确保读取到最新值(避免CPU缓存导致的脏读)return Interlocked.CompareExchange(ref _state, 0, 0) == 1;}#endregion#region 计数器场景(原子增减)/// <summary>/// 原子递增状态值(+1)/// </summary>/// <returns>递增后的新值</returns>public static int Increment(){return Interlocked.Increment(ref _state);}/// <summary>/// 原子递减状态值(-1)/// </summary>/// <returns>递减后的新值</returns>public static int Decrement(){return Interlocked.Decrement(ref _state);}/// <summary>/// 原子读取当前计数值/// </summary>/// <returns>当前状态值</returns>public static int GetCount(){return Interlocked.CompareExchange(ref _state, 0, 0);}#endregion#region 高级场景:条件更新(仅当满足条件时修改)/// <summary>/// 仅当当前状态为“关闭”时,原子设置为“开启”/// </summary>/// <returns>True=更新成功,False=当前状态不满足条件</returns>public static bool EnableIfDisabled(){// 比较并交换:若当前值为0(关闭),则更新为1(开启)int originalValue = Interlocked.CompareExchange(ref _state, 1, 0);return originalValue == 0; // 若原始值为0,说明更新成功}/// <summary>/// 仅当当前状态为目标值时,原子更新为新值/// </summary>/// <param name="expectedValue">预期当前值</param>/// <param name="newValue">目标新值</param>/// <returns>True=更新成功,False=当前值不符预期</returns>public static bool UpdateIfMatch(int expectedValue, int newValue){int originalValue = Interlocked.CompareExchange(ref _state, newValue, expectedValue);return originalValue == expectedValue;}#endregion
}
使用示例csharp
class Program
{static void Main(){// 1. 开关状态场景AtomicStateManager.Enable();Console.WriteLine($"是否开启:{AtomicStateManager.IsEnabled()}"); // 输出:TrueAtomicStateManager.Toggle();Console.WriteLine($"切换后是否开启:{AtomicStateManager.IsEnabled()}"); // 输出:Falsebool updateSuccess = AtomicStateManager.EnableIfDisabled();Console.WriteLine($"是否成功开启:{updateSuccess}"); // 输出:TrueConsole.WriteLine($"当前状态:{AtomicStateManager.IsEnabled()}"); // 输出:True// 2. 计数器场景AtomicStateManager.Increment(); // 状态从1→2AtomicStateManager.Increment(); // 状态从2→3Console.WriteLine($"当前计数:{AtomicStateManager.GetCount()}"); // 输出:3AtomicStateManager.Decrement(); // 状态从3→2Console.WriteLine($"递减后计数:{AtomicStateManager.GetCount()}"); // 输出:2// 3. 条件更新场景bool conditionUpdate = AtomicStateManager.UpdateIfMatch(2, 100);Console.WriteLine($"条件更新是否成功:{conditionUpdate}"); // 输出:TrueConsole.WriteLine($"更新后的值:{AtomicStateManager.GetCount()}"); // 输出:100}
}
核心原理与优势
-
原子性保证:
Interlocked
类的方法通过底层硬件指令实现原子操作,确保操作过程不会被其他线程打断,避免竞态条件。 -
性能优化:
相比lock
等锁机制,Interlocked
操作无需上下文切换,开销更小,适合高频访问场景。 -
可见性保证:
所有Interlocked
操作会强制刷新 CPU 缓存,确保所有线程看到的是最新值,避免因缓存导致的数据不一致。 -
灵活性扩展:
示例中用0
和1
表示开关状态,实际可扩展为多状态(如0=未初始化
、1=运行中
、2=已停止
),通过UpdateIfMatch
方法实现复杂状态转换。
这种方式特别适合 IIS 等多线程环境下的全局变量控制,可有效避免并发修改导致的异常。
VB.NET的用法例子:
将布尔值转换为整数类型(如 Integer
)后使用 Interlocked
类的原子操作(如递增、递减、比较交换),在多线程场景中会更直观且高效。这种方式特别适合需要 "开关状态切换" 或 "计数控制" 的场景。
以下是 VB.NET 中基于整数类型的原子操作实现,以 GetServerInfo
的状态控制为例:
实现示例:VB.NET 用整数类型模拟状态,结合原子操作
vb
Imports System.Threading' 用整数表示状态:0=关闭(False),1=开启(True)
Private Shared _serverInfoState As Integer = 0 ' 初始状态:关闭' 原子开启(设置为1)
Public Sub EnableServerInfo()Interlocked.Exchange(_serverInfoState, 1)
End Sub' 原子关闭(设置为0)
Public Sub DisableServerInfo()Interlocked.Exchange(_serverInfoState, 0)
End Sub' 原子切换状态(0→1 或 1→0)
Public Sub ToggleServerInfo()' 循环尝试切换,直到成功(处理并发冲突)DoDim currentState = _serverInfoStateDim newState = If(currentState = 1, 0, 1)' 比较并交换:如果当前值仍为 currentState,则更新为 newStateLoop While Interlocked.CompareExchange(_serverInfoState, newState, currentState) <> currentState
End Sub' 原子读取当前状态
Public Function IsServerInfoEnabled() As Boolean' 读取操作本身是原子的,但用 CompareExchange 确保可见性Return Interlocked.CompareExchange(_serverInfoState, 0, 0) = 1
End Function' 原子递增(适合计数场景)
Public Sub IncrementCounter()Interlocked.Increment(_serverInfoState)
End Sub' 原子递减(适合计数场景)
Public Sub DecrementCounter()Interlocked.Decrement(_serverInfoState)
End Sub
优势说明
-
操作直观:
用0
和1
对应False
和True
,通过Interlocked.Increment
/Decrement
可直接实现计数,无需额外转换逻辑。 -
性能优异:
Interlocked
类的方法是底层硬件支持的原子操作,比SyncLock
等锁机制开销更小,尤其适合高频访问的场景。 -
避免竞态条件:
Exchange
确保 "设置新值" 操作的原子性,不会被其他线程打断。CompareExchange
结合循环可实现 "检查 - 更新" 的原子性(如ToggleServerInfo
方法),避免并发下的状态不一致。
-
可见性保证:
Interlocked
操作会强制刷新 CPU 缓存,确保所有线程看到的是最新值(避免因缓存导致的 "脏读")。
适用场景
- 简单的开关状态(如
GetServerInfo
的启用 / 禁用)。 - 计数器(如统计并发请求数、操作次数)。
- 需要原子 "检查并修改" 的逻辑(如仅当状态为关闭时才开启)。
如果你的场景涉及更复杂的状态转换(如多值状态),这种整数映射方式同样适用,只需扩展数值对应的含义即可(如 0=未初始化
、1=运行中
、2=已停止
)。