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

基于锁的读写者多线程程序崩溃,求代码问题排查

问题排查与修复

崩溃根源

抛出std::system_error: Operation not permitted异常的核心原因是:线程尝试解锁一个自己并未持有锁的互斥量。

  • 只有第一个进入的Reader线程会通过writeLocker.lock()锁定wmu,其余Reader线程的writeLocker从未被锁定
  • 当最后一个Reader线程退出时,无论它是否是最初锁定wmu的线程,都会执行writeLocker.unlock(),未持有锁的线程执行此操作会触发非法操作异常

修复方案

方案1:标记锁持有状态

在Reader函数中增加局部变量,标记当前线程是否持有写锁,仅当持有锁时才执行解锁操作:

void Reader()
{
    unique_lock<mutex> readLocker(rmu, std::defer_lock);
    unique_lock<mutex> writeLocker(wmu, std::defer_lock);
    bool hasWriteLock = false;

    readLocker.lock();
    readCount++;
    if (readCount == 1)
    {
        writeLocker.lock();
        hasWriteLock = true; // 标记当前线程持有写锁
    }
    readLocker.unlock();

    cout << "Reader " << count << endl;

    readLocker.lock();
    readCount--;
    if (readCount == 0 && hasWriteLock) 
    {
        writeLocker.unlock(); // 仅持有锁时执行解锁
    }
    readLocker.unlock();
}

方案2:经典读写者模型(条件变量优化)

改用条件变量配合互斥量的实现,从根源避免锁管理混乱:

#include<iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;

class ReaderAndWriter
{
    mutex mtx;
    condition_variable cv;
    int count = 20;
    int readCount{ 0 };
    bool isWriting = false;

public:
    void Reader()
    {
        unique_lock<mutex> locker(mtx);
        // 等待写操作完成
        while (isWriting)
        {
            cv.wait(locker);
        }
        readCount++;
        locker.unlock();

        cout << "Reader " << count << endl;

        locker.lock();
        readCount--;
        if (readCount == 0)
        {
            cv.notify_all(); // 通知等待的写线程
        }
        locker.unlock();
    }

    void Writer()
    {
        unique_lock<mutex> locker(mtx);
        // 等待无读者且无其他写者
        while (readCount > 0 || isWriting)
        {
            cv.wait(locker);
        }
        isWriting = true;
        locker.unlock();

        count++;
        cout << "writer " << count << endl;

        locker.lock();
        isWriting = false;
        cv.notify_all(); // 通知所有等待的读/写线程
        locker.unlock();
    }

    void run()
    {
        std::thread reader1(&ReaderAndWriter::Reader, this);
        std::thread reader2(&ReaderAndWriter::Reader, this);
        std::thread reader3(&ReaderAndWriter::Reader, this);

        std::thread writer1(&ReaderAndWriter::Writer, this);
        std::thread writer2(&ReaderAndWriter::Writer, this);

        reader1.join();
        reader2.join();
        reader3.join();

        writer1.join();
        writer2.join();

        cout << "Success" << endl;
    }
};

int main()
{
    ReaderAndWriter rw;
    rw.run();
    return 0;
}

额外注意事项

  • cout是线程不安全的,多线程同时输出会导致乱码,建议给cout单独加锁保护
  • 原代码main函数返回true不符合C++标准,应返回0表示正常退出

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 15:40:37