基于锁的读写者多线程程序崩溃,求代码问题排查
问题排查与修复
崩溃根源
抛出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
相关产品推荐
相关产品推荐

