C++怎么实现一个读写锁

来源:程序开发作者:弥生美月头衔:网络博主
导读:本期聚焦于小伙伴创作的《C++怎么实现一个读写锁》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《C++怎么实现一个读写锁》有用,将其分享出去将是对创作者最好的鼓励。

C++读写锁的核心设计思路

读写锁的核心目标是区分读操作和写操作的访问权限,读操作之间可以共享资源,读操作和写操作、写操作和写操作之间需要互斥。实现时需要维护几个关键状态:当前活跃的读线程数量、是否有写线程正在等待或持有锁、等待队列的处理逻辑。我们可以借助C++标准库的std::mutex保护内部状态,用std::condition_variable实现线程的等待和唤醒。

C++怎么实现一个读写锁

核心状态定义

首先需要定义读写锁的内部状态变量,包括读计数、写标志、等待写计数,同时搭配互斥量和条件变量:

#include <mutex>
#include <condition_variable>
#include <atomic>

class ReadWriteLock {
private:
    std::mutex mtx;                 // 保护内部状态的互斥量
    std::condition_variable read_cv; // 读线程等待的条件变量
    std::condition_variable write_cv;// 写线程等待的条件变量
    int read_count = 0;             // 当前持有读锁的线程数
    int write_count = 0;            // 等待或持有写锁的线程数
    bool is_writing = false;        // 是否有线程正在写
};

读锁的获取与释放

读锁的获取逻辑需要满足:如果没有写线程正在操作或等待,就可以增加读计数并获取锁;如果有写线程等待,读线程需要进入等待队列,避免写线程饥饿。

public:
    // 获取读锁
    void lock_read() {
        std::unique_lock<std::mutex> lock(mtx);
        // 等待条件:没有写线程正在操作,且没有写线程在等待
        read_cv.wait(lock, [this]() {
            return !is_writing && write_count == 0;
        });
        read_count++;
    }

    // 释放读锁
    void unlock_read() {
        std::unique_lock<std::mutex> lock(mtx);
        read_count--;
        // 如果读计数归零,且存在等待的写线程,唤醒一个写线程
        if (read_count == 0 && write_count > 0) {
            write_cv.notify_one();
        }
    }

写锁的获取与释放

写锁的获取逻辑需要满足:如果没有任何读线程持有锁,且没有写线程正在操作,就可以获取写锁;否则进入等待队列,等待所有读线程释放锁且写线程释放锁。

    // 获取写锁
    void lock_write() {
        std::unique_lock<std::mutex> lock(mtx);
        write_count++;
        // 等待条件:没有读线程持有锁,且没有写线程正在操作
        write_cv.wait(lock, [this]() {
            return read_count == 0 && !is_writing;
        });
        is_writing = true;
        write_count--;
    }

    // 释放写锁
    void unlock_write() {
        std::unique_lock<std::mutex> lock(mtx);
        is_writing = false;
        // 优先唤醒等待的写线程,如果没有写线程等待再唤醒所有读线程
        if (write_count > 0) {
            write_cv.notify_one();
        } else {
            read_cv.notify_all();
        }
    }
};

读写锁的使用示例

下面通过一个简单的共享数据访问示例,展示我们实现的读写锁的使用方式:

#include <iostream>
#include <thread>
#include <vector>

int shared_data = 0;
ReadWriteLock rw_lock;

// 读线程函数
void read_task(int thread_id) {
    rw_lock.lock_read();
    std::cout << "线程" << thread_id << "读取共享数据:" << shared_data << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    rw_lock.unlock_read();
}

// 写线程函数
void write_task(int thread_id, int value) {
    rw_lock.lock_write();
    shared_data = value;
    std::cout << "线程" << thread_id << "写入共享数据:" << shared_data << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(200));
    rw_lock.unlock_write();
}

int main() {
    std::vector<std::thread> threads;
    // 创建3个写线程
    for (int i = 0; i < 3; i++) {
        threads.emplace_back(write_task, i, i + 10);
    }
    // 创建5个读线程
    for (int i = 0; i < 5; i++) {
        threads.emplace_back(read_task, i + 3);
    }
    // 等待所有线程结束
    for (auto& t : threads) {
        t.join();
    }
    return 0;
}

实现注意事项

  • 写线程优先策略:上述实现中写线程等待时,读线程不会继续获取锁,避免写线程长时间等待,适合写操作需要及时执行的场景。
  • 条件变量的虚假唤醒:使用std::condition_variable::wait时必须传入谓词,避免虚假唤醒导致状态错误。
  • 锁的配对使用:获取读锁必须对应释放读锁,获取写锁必须对应释放写锁,否则会导致状态异常或死锁。
  • C++17及以上标准已经提供了std::shared_mutex,实际开发中如果不是需要自定义读写锁逻辑,优先使用标准库提供的实现,可靠性和性能更有保障。

C++读写锁C++并发编程读写锁实现std_thread修改时间:2026-06-26 12:54:30

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。