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

C#非恒定条件下的条件线程锁实现方案验证咨询

动态条件场景下的条件线程锁实现验证

核心需求

实现一套按需加锁的线程同步逻辑,满足:

  • 线程安全方法A支持多线程高并发执行,无额外锁开销
  • 非线程安全方法B执行时,完全阻塞A的执行,避免并发访问导致的数据错误
  • 禁止使用全局全量加锁,满足缓存组件的极高性能要求

原有存在竞态的基础逻辑如下:

if (condition)
{
    A();
}
else
{
    B();
}

// 方法属性说明
// A:线程安全,基于并发字典实现缓存键更新计数累加
// B:非线程安全,负责处理更新记录、重排缓存优先级结构、淘汰最低优先级条目,原实现通过[MethodImpl(MethodImplOptions.Synchronized)]标记同步

其中判断条件condition为「请求的目标数据是否存在于缓存中」,B执行过程中会修改缓存结构、删除条目,可能导致正在执行A的线程访问已删除数据抛出错误。

已知的经典竞态场景

直接使用读写锁但未正确覆盖锁范围时,会出现如下问题:

线程1判断缓存命中(condition=true),准备调用A前发生线程切换;线程2触发缓存未命中,执行B完成结构重排和条目淘汰,恰好删除了线程1要访问的缓存键;线程1恢复执行A时,访问已删除条目触发错误。

待验证的自定义实现

_lock.EnterReadLock();
if (condition)
{
    A();
}
_lock.ExitReadLock();

if (!condition)
{
    B();
}

void A()
{
   // 缓存命中:并发字典累加更新计数
}

void B()
{
    _lock.EnterWriteLock();
    // 缓存未命中:处理更新、重排结构、淘汰条目
    _lock.ExitWriteLock();
}

方案有效性结论:无法解决竞态问题,存在两处致命缺陷

  • 缺陷1:B的触发判断无锁保护,会导致重复执行
    释放读锁后到B获取写锁前存在时间窗口,可能有多个线程同时读到condition=false,随后依次进入B获取写锁执行,重复触发结构重排、条目淘汰逻辑,既浪费性能,还可能因重复淘汰导致缓存数据错乱。
  • 缺陷2:锁范围未覆盖空窗期,A/B并发问题依然存在
    读锁释放后、B拿到写锁前,可能有新的线程成功获取读锁进入A执行。等B拿到写锁开始修改结构、删除条目时,这个正在运行的A依然会访问到已删除的条目,最初要规避的竞态问题完全没有被解决。

修正后的高性能实现方案

调整锁的覆盖范围,结合双重检查逻辑,既保证并发性能,又彻底消除竞态:

// 注意:生产环境优先使用ReaderWriterLockSlim,性能远优于旧版ReaderWriterLock
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();

public void ProcessRequest(string key)
{
    while (true)
    {
        // 快路径:缓存命中场景走读锁,支持多线程完全并发,无串行开销
        _lock.EnterReadLock();
        try
        {
            if (condition /* 缓存Key存在判断 */)
            {
                A();
                return;
            }
        }
        finally
        {
            _lock.ExitReadLock();
        }

        // 慢路径:缓存未命中时升级写锁,阻塞所有新的读请求
        _lock.EnterWriteLock();
        try
        {
            // 双重检查:等待写锁期间可能有其他线程已经完成了缓存加载,直接重试走快路径
            if (condition)
            {
                continue;
            }
            B();
            return;
        }
        finally
        {
            _lock.ExitWriteLock();
        }
    }
}

void A()
{
    // 缓存命中逻辑:并发字典累加更新计数
}

void B()
{
    // 缓存未命中逻辑:处理更新记录、重排优先级结构、淘汰最低优先级条目、加载新缓存条目
}

该方案的优势:

  • 占比绝大多数的缓存命中场景全程只持有读锁,多线程无阻塞并发,完全满足高性能要求
  • 只有缓存未命中的场景才会申请写锁,写锁持有期间所有新读请求会被阻塞,保证B执行时没有线程在运行A,彻底消除访问已删除条目的竞态
  • 写锁入口的双重检查逻辑,避免了多线程重复执行B的重排、淘汰逻辑,减少无效性能损耗

注:ReaderWriterLockSlim是.NET官方推荐的高并发场景读写锁实现,相比旧版ReaderWriterLock没有线程亲和性带来的性能开销,递归锁检测机制也能规避大部分死锁风险,更适合缓存组件场景。


内容的提问来源于stack exchange,提问作者Kartik Mahajan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 02:45:50