You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# 基于Interlocked实现无锁线程安全MaxCounter的优化方案咨询

线程安全最大值计数器的CompareExchange优化方案

现有实现的问题

你当前的实现存在竞态条件:Interlocked.Read 和后续的Interlocked.Exchange是两个独立的原子操作,两个操作之间存在时间窗口。比如线程A读取当前值为5,准备写入6;同时线程B读取当前值也为5,准备写入7。两个线程都通过了value > 当前值的判断,最终可能出现线程B先写入7,线程A后写入6,导致最终值为6的错误结果,完全不符合最大值计数器的预期。

优化可行性

使用Interlocked.CompareExchange实现完全可行,是无锁场景下实现此类比较更新逻辑的标准方案,它可以将「比较当前值是否匹配」和「写入新值」两个操作合并为单个原子操作,彻底消除竞态窗口。

具体实现

class MaxCounter
{
    private int _value = int.MinValue;

    public void Max(int value)
    {
        int currentValue;
        // 循环重试直到更新成功或无需更新
        while (true)
        {
            // 原子读取当前最新值
            currentValue = Interlocked.Read(ref _value);
            // 当前值已经大于等于传入值,不需要更新,直接退出
            if (value <= currentValue)
            {
                return;
            }
            // 原子比较替换:如果_value当前值等于currentValue,就替换为value,返回替换前的_value值
            int originalValue = Interlocked.CompareExchange(ref _value, value, currentValue);
            // 返回的原始值等于读取的currentValue,说明替换成功
            if (originalValue == currentValue)
            {
                Console.WriteLine("Thread {0} updated counter to {1}.", Thread.CurrentThread.ManagedThreadId, value);
                return;
            }
            // 替换失败说明其他线程已经修改了_value,回到循环开头重新判断
        }
    }

    // 读取值也需要原子操作,保证拿到最新值
    public int Value => Interlocked.Read(ref _value);
}

实现说明

  • 循环重试机制的开销极低,仅在多线程同时竞争更新的时候会触发少量重试,绝大多数场景下性能远优于锁实现。
  • 所有对_value的读写都通过Interlocked操作完成,既保证了原子性,也避免了CPU缓存导致的内存可见性问题。
  • 即便出现ABA问题(值被改走又改回),也不会影响最大值计数器的逻辑正确性:如果值被改成更大的数又改回原来的值,说明中间出现过更大的值,此时当前传入的值即使等于原来的读取值,也不需要更新,逻辑完全自洽。

内容的提问来源于stack exchange,提问作者Gilbert Williams

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 16:54:04