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

确认公平读写者票锁的并发能力及设计逻辑合理性

公平共享票锁的设计验证与并发能力分析

问题描述

我正在实现一款简单的公平共享票锁,目标是让到达的读者和写者都能获得公平对待,核心规则如下:

  • 所有请求者进入同一队列
  • 队列中连续的读者组可并发访问
  • 写者需等待其前方所有读者完成后再获取访问权
  • 写者解锁后,下一组连续读者可获取访问权

代码实现

// SharedTicketLock.h
#pragma once
#include <atomic>
#include <thread>

class SharedTicketLock {
    std::atomic<uint16_t> next_ticket{0};
    std::atomic<uint16_t> now_serving{0};
    std::atomic<uint16_t> served{0};

public:
    void writer_lock(){
        uint16_t my_ticket = next_ticket.fetch_add(2);
        while (now_serving.load() != my_ticket || now_serving.load() != served.load()){
            std::this_thread::yield();
        }
    }

    void reader_lock(){
        uint16_t my_ticket = next_ticket.fetch_add(1);
        while (now_serving.load() != my_ticket){
            std::this_thread::yield();
        }
        now_serving.fetch_add(1);
    }

    void reader_unlock(){
        served.fetch_add(1);
    }

    void writer_unlock(){
        now_serving.fetch_add(2);
        served.fetch_add(2);
    }
};

设计思路

  • 在传统票锁基础上新增原子计数器served,用于跟踪已离开临界区的请求者数量
  • 写者获取2个票号(next_ticket.fetch_add(2)),读者仅获取1个票号
  • 读者在now_serving等于自身票号时进入临界区,进入后立即递增now_serving,允许后续同组读者并发进入
  • 写者需同时满足now_serving等于自身票号且now_serving == served时才能进入,确保前方所有请求者已完全离开临界区
  • 写者加锁时不递增now_serving,通过2个票号的间隔阻止后续请求者提前进入
  • 读者解锁时递增served,让后续写者能判断前方读者是否全部完成
  • 写者解锁时同时递增now_serving和served各2,通知后续请求者写者已释放锁
  • 依赖uint16_t的自然溢出,通过相等判断处理票号循环问题

疑问

  1. 该锁的并发能力如何?
  2. 上述设计推理是否合理?

设计合理性与并发能力分析

一、设计推理的合理性判断

整体设计符合公平性核心要求,通过票号间隔区分读者/写者权限,实现了队列化的公平调度:

  • 公平性保障:所有请求者通过next_ticket按到达顺序获取票号,严格遵循先到先服务,不会出现写者或读者饥饿的情况
  • 读者并发逻辑:连续读者的票号连续递增,第一个读者进入后立即推进now_serving,后续读者只要票号匹配就能直接进入,完美实现同组读者的并发访问,符合规则要求
  • 写者等待逻辑:写者票号为偶数(初始从0开始),需等待served == now_serving确保前方所有读者已解锁离开,解锁后同步推进now_serving和served,让后续请求者继续执行,完全匹配规则3、4
  • 溢出处理:利用uint16_t无符号整数的模2^16溢出特性,通过相等判断处理票号循环,逻辑可行(无符号整数溢出在C++中是定义良好的行为)

但设计存在几个潜在细节问题:

  1. 内存序优化空间:代码中所有原子操作使用默认的memory_order_seq_cst,虽保证顺序一致性,但性能冗余,可将load改为memory_order_acquire、fetch_add改为memory_order_release,不影响正确性但能降低同步开销
  2. 循环等待的效率:仅使用yield()在高并发场景下可能导致频繁线程切换,可考虑加入短暂休眠(如std::this_thread::sleep_for(std::chrono::nanoseconds(10)))平衡CPU占用与响应速度

二、并发能力分析

  • 读者并发效率:同一组读者可完全并发进入临界区,仅需等待票号匹配(而非前序读者解锁),并发能力接近无锁读者模式,仅存在原子操作的微小开销
  • 写者性能特性:写者需等待前方所有读者完成,这是公平读写锁的固有特性,此处通过served精准跟踪已完成请求,等待逻辑高效,无额外冗余判断
  • 全局竞争点:next_ticket的fetch_add是唯一全局竞争点,这是票锁类结构的固有问题,但相较于其他公平读写锁,该实现的竞争规模已处于较低水平
  • 整体吞吐量:在读者占比高的场景下,吞吐量接近普通读写锁;写者占比高时,吞吐量与公平互斥锁相当,符合公平锁的性能预期

三、总结

该设计核心逻辑合理,完全满足设定的公平性与访问规则,并发能力在公平读写锁中处于较好水平,仅需针对内存序和等待逻辑做细节优化即可进一步提升性能。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 01:53:17