C#vb.net中Interlocked类实现原子操作加减计算,涵盖状态切换、计数控制等常见场景

发布于:2025-08-13 ⋅ 阅读:(20) ⋅ 点赞:(0)

以下是 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()}"); // 输出:True

        AtomicStateManager.Toggle();
        Console.WriteLine($"切换后是否开启:{AtomicStateManager.IsEnabled()}"); // 输出:False

        bool updateSuccess = AtomicStateManager.EnableIfDisabled();
        Console.WriteLine($"是否成功开启:{updateSuccess}"); // 输出:True
        Console.WriteLine($"当前状态:{AtomicStateManager.IsEnabled()}"); // 输出:True


        // 2. 计数器场景
        AtomicStateManager.Increment(); // 状态从1→2
        AtomicStateManager.Increment(); // 状态从2→3
        Console.WriteLine($"当前计数:{AtomicStateManager.GetCount()}"); // 输出:3

        AtomicStateManager.Decrement(); // 状态从3→2
        Console.WriteLine($"递减后计数:{AtomicStateManager.GetCount()}"); // 输出:2


        // 3. 条件更新场景
        bool conditionUpdate = AtomicStateManager.UpdateIfMatch(2, 100);
        Console.WriteLine($"条件更新是否成功:{conditionUpdate}"); // 输出:True
        Console.WriteLine($"更新后的值:{AtomicStateManager.GetCount()}"); // 输出:100
    }
}

核心原理与优势

  1. 原子性保证
    Interlocked 类的方法通过底层硬件指令实现原子操作,确保操作过程不会被其他线程打断,避免竞态条件。

  2. 性能优化
    相比 lock 等锁机制,Interlocked 操作无需上下文切换,开销更小,适合高频访问场景。

  3. 可见性保证
    所有 Interlocked 操作会强制刷新 CPU 缓存,确保所有线程看到的是最新值,避免因缓存导致的数据不一致。

  4. 灵活性扩展
    示例中用 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()
    ' 循环尝试切换,直到成功(处理并发冲突)
    Do
        Dim currentState = _serverInfoState
        Dim newState = If(currentState = 1, 0, 1)
        ' 比较并交换:如果当前值仍为 currentState,则更新为 newState
    Loop 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

优势说明

  1. 操作直观
    用 0 和 1 对应 False 和 True,通过 Interlocked.Increment/Decrement 可直接实现计数,无需额外转换逻辑。

  2. 性能优异
    Interlocked 类的方法是底层硬件支持的原子操作,比 SyncLock 等锁机制开销更小,尤其适合高频访问的场景。

  3. 避免竞态条件

    • Exchange 确保 "设置新值" 操作的原子性,不会被其他线程打断。
    • CompareExchange 结合循环可实现 "检查 - 更新" 的原子性(如 ToggleServerInfo 方法),避免并发下的状态不一致。
  4. 可见性保证
    Interlocked 操作会强制刷新 CPU 缓存,确保所有线程看到的是最新值(避免因缓存导致的 "脏读")。

适用场景

  • 简单的开关状态(如 GetServerInfo 的启用 / 禁用)。
  • 计数器(如统计并发请求数、操作次数)。
  • 需要原子 "检查并修改" 的逻辑(如仅当状态为关闭时才开启)。

如果你的场景涉及更复杂的状态转换(如多值状态),这种整数映射方式同样适用,只需扩展数值对应的含义即可(如 0=未初始化1=运行中2=已停止)。


网站公告

今日签到

点亮在社区的每一天
去签到