引入
随着多线程编程越来越受到开发者的青睐,C++标准库中的 <mutex> 头文件提供了许多工具以支持安全的并发编程。C++17 引入的 std::shared_mutex 是一种进阶的互斥量,它允许多个线程可以同时以共享方式访问同一个资源,但又确保在读操作时,如果有线程执行写操作,则不能读取。std::shared_mutex::lock_shared 方法专门用于申请共享锁,允许多个线程同时读取,而不干扰其它线程的读操作。正确理解并使用这一方法,对于设计高效的并发程序至关重要。
1. 特性与函数介绍
1.1 特性
- 共享访问:
lock_shared()方法支持多个线程并发读取共享资源,而不需要获取独占锁。这有助于在读多写少的场景中提高并行性能。 - 线程安全:在写入操作未完成的情况下,无法进行读取操作,确保了对共享资源的安全性和一致性。
- 灵活性:适用于复杂的多线程应用,同时支持区别读写访问,提高了代码的灵活性。
1.2 函数语法
std::shared_mutex::lock_shared 的基本语法如下:
#include <mutex>
class shared_mutex : public mutex {
public:
void lock_shared(); // 申请共享锁
...
};
- 无参数:此函数的调用不需要任何参数。
- 无返回值:成功获取共享锁后不会返回任何值。
2. 完整示例代码
以下示例展示了如何使用 std::shared_mutex::lock_shared 在多线程环境中安全地进行读取操作。
#include <iostream>
#include <thread>
#include <mutex>
#include <shared_mutex>
#include <vector>
std::shared_mutex smtx; // 定义共享互斥锁
std::vector<int> sharedData; // 共享数据区域
// 读取数据的函数
void readData() {
smtx.lock_shared(); // 申请共享锁
std::cout << "Thread " << std::this_thread::get_id()
<< " read values: ";
for (const auto& val : sharedData) {
std::cout << val << " "; // 输出共享数据
}
std::cout << std::endl;
smtx.unlock_shared(); // 释放共享锁
}
// 写入数据的函数
void writeData(int value) {
smtx.lock(); // 申请独占锁
sharedData.push_back(value);
std::cout << "Thread " << std::this_thread::get_id()
<< " wrote value: " << value << std::endl;
smtx.unlock(); // 释放独占锁
}
int main() {
const int numWriters = 3; // 写线程数量
const int numReaders = 2; // 读线程数量
std::thread writers[numWriters];
std::thread readers[numReaders];
// 启动写线程
for (int i = 0; i < numWriters; ++i) {
writers[i] = std::thread(writeData, i + 1);
}
// 启动读线程
for (int i = 0; i < numReaders; ++i) {
readers[i] = std::thread(readData);
}
// 等待所有线程完成
for (auto& writer : writers) {
writer.join();
}
for (auto& reader : readers) {
reader.join();
}
return 0;
}
3. 代码解析
-
引入必要的头文件:
- 本示例引入
<mutex>、<thread>、<shared_mutex>和<vector>等头文件,以支持互斥量和线程操作,以及数据结构。
- 本示例引入
-
定义共享数据和互斥锁:
- 创建
std::shared_mutex smtx:供多个线程一起使用,以及一个sharedData向量作为共享数据的容器。
- 创建
-
定义读取函数:
readData函数通过smtx.lock_shared()申请共享锁,允许多个线程同时读取共享数据;读取后,使用smtx.unlock_shared()释放共享锁。
-
定义写入函数:
writeData函数通过smtx.lock()申请独占锁来进行写入,并如法提供安全的数据操作,最后释放锁。
-
主函数/thread管理:
- 在
main函数中,创建写线程和读线程,顺序启动并使用join()等待所有子线程执行结束。
- 在
4. 适用场景分析
4.1 读多写少的场景
在大量读取操作且较少写入的应用中,使用 std::shared_mutex::lock_shared 能带来较高的并发性能,例如日志记录、浏览状态信息等。
4.2 数据分享与统计系统
例如历史记录表现的系统允许同时向用户展示程序指标,lock_shared 能确保多个读取者无阻塞并获得实时数据。
4.3 服务访问控制
在网络应用或数据库的多个读操作请求时,一般需要保持数据一致,使用共享锁实现并行访问保证性能。
5. 总结
std::shared_mutex::lock_shared 提供了一种强大的工具,简化了跨线程访问共享数据的权限控制。通过允许多个线程并行读取,而在写入时保持对资源的独占性,它极大地提升了高并发环境下程序的效率和响应能力。合理使用 std::shared_mutex 将推动开发者在复杂的多线程场景中设计出更高效的系统。掌握这一机制不仅能够避免潜在的数据冲突,还能保证读取的数据一致性,为实现多线程程序提供更加稳固和优质的基础。



没有回复内容