C++ 17实现读写锁
在C++中,实现读写锁可以使用std::shared_mutex
,它是C++17标准中引入的。读写锁允许多个线程同时读取一个共享资源,但在写入时,只允许一个线程对资源进行写入,并阻止其他线程读取或写入。
下面是使用std::shared_mutex
实现读写锁的示例代码,包括一个简单的共享数据访问类和在main
函数中的测试:
#include <iostream>
#include <shared_mutex>
#include <string>
#include <thread>
#include <vector>
#include <mutex>
class SharedData {
private:
int data;
mutable std::shared_mutex mutex;
public:
SharedData(int initial_data) : data(initial_data) {}
// 读取数据的函数
int readData() const {
std::shared_lock<std::shared_mutex> lock(mutex);
// 假设读取数据需要一些时间
std::this_thread::sleep_for(std::chrono::milliseconds(100));
return data;
}
// 写入数据的函数
void writeData(int new_data) {
std::unique_lock<std::shared_mutex> lock(mutex);
// 假设写入数据需要一些时间
std::this_thread::sleep_for(std::chrono::milliseconds(100));
data = new_data;
}
};
int main() {
SharedData sharedData(0);
// 创建多个线程进行读写操作
std::vector<std::thread> threads;
// 启动一些读取线程
for (int i = 0; i < 5; ++i) {
threads.push_back(std::thread([&sharedData, i]() {
std::cout << "Thread " << i << " read data: " << sharedData.readData() << std::endl;
}));
}
// 启动一些写入线程
for (int i = 0; i < 2; ++i) {
threads.push_back(std::thread([&sharedData, i]() {
sharedData.writeData(i * 10);
std::cout << "Thread " << i + 5 << " wrote data: " << i * 10 << std::endl;
}));
}
// 等待所有线程完成
for (auto& thread : threads) {
thread.join();
}
return 0;
}
在这个示例中:
SharedData
类中使用std::shared_mutex
来实现读写锁。readData
方法使用std::shared_lock
来获取共享锁,允许多个线程同时读取数据。writeData
方法使用std::unique_lock
来获取独占锁,只允许一个线程写入数据。main
函数中创建了多个线程,模拟并发读写场景。
编译这段代码需要支持C++17的编译器,使用如下编译指令:
g++ -std=c++17 your_file_name.cpp -o your_program -lpthread
替换 your_file_name.cpp
和 your_program
为你的文件名和希望生成的程序名。这段代码在一个多线程环境下测试了读写锁的工作方式。
mutable关键字有什么作用
在C++中,mutable
关键字用于声明一个类成员变量,表示即使在一个 const
成员函数内部,该变量也可以被修改。通常情况下,const
成员函数中不允许修改任何成员变量,因为这样的函数承诺不会修改对象的状态。
在上面的代码中,mutable
关键字用于 std::shared_mutex
类型的 mutex
成员变量:
mutable std::shared_mutex mutex;
这样使用的原因是即使在 const
成员函数中,也需要能够对 mutex
进行锁定和解锁操作。锁定和解锁操作会修改 mutex
的内部状态,但这种修改并不违背 const
函数的语义,即不会改变对象的公共状态或逻辑状态。
具体来说,在 readData
函数中:
int readData() const {
std::shared_lock<std::shared_mutex> lock(mutex);
...
}
尽管 readData
被声明为 const
,表示它不会修改 SharedData
对象的逻辑状态,我们仍然需要对 mutex
进行操作以确保线程安全。使用 mutable
关键字可以实现这一点,它使得即使在 const
方法中,也可以对 mutex
进行加锁和解锁操作,而不违反 const
方法的约定。这允许在保持数据成员不变的情况下进行同步操作,是多线程编程中一种常见的模式。
std::shared_lock和std::unique_lock的区别
std::shared_lock 和 std::unique_lock 是 C++ 标准库中的两种锁管理器,它们都用于管理某种互斥量(mutex)的锁定状态,但是用途和特性有所不同。
std::unique_lock
std::unique_lock 是一个通用的互斥锁管理器,它可以用于任何互斥量。
它提供了对互斥量的独占控制,即在同一时间内只有一个 std::unique_lock 可以持有互斥量。
它比 std::lock_guard 更灵活,允许延迟锁定、尝试锁定、时间锁定以及手动锁定和解锁。
通常用于需要细粒度控制互斥量的场景。
std::shared_lock
std::shared_lock 是用于管理共享互斥量(例如 std::shared_mutex)的锁管理器。
它提供了对互斥量的共享控制,允许多个 std::shared_lock 同时持有互斥量,但在任何 std::unique_lock 持有互斥量时,无法获取。
主要用于实现读写锁模式,其中读操作可以并发执行,但写操作必须独占访问。