引入
在多线程编程中,合理有效地管理对共享资源的访问,对于维护程序的稳定性及安全性至关重要。C++11 引入的 <mutex> 和 <shared_mutex> 头文件为这一需求提供了多种解决方案。其中,C++17 引入的 std::shared_lock<Mutex> 打破了传统的锁定机制,允许多个线程同时读取资源,同时在进行写操作时独占互斥量。与之相应,std::shared_lock<Mutex>::try_lock 方法允许线程尝试获取共享锁,并根据当前锁的状态快速返回。这一特性在高并发访问情景中尤为重要,能够提高应用的响应速度与性能。
1. 特性与函数介绍
1.1 特性
- 非阻塞性尝试获得共享锁:使用
try_lock方法可以尝试获取共享锁,而不必等待锁的可用性。在锁被其他线程占用时,它会立即返回失败的信息。 - 高效并发读取:多个线程可以同时持有共享锁,使大量读取操作能够并行进行,这对于构建高性能的多用户应用尤为重要。
- 提高灵活性:通过
try_lock,可以在特定条件下选择能够继续执行其他操作,而不会因等待锁而导致性能下降。
1.2 函数语法
std::shared_lock<Mutex>::try_lock 的基本语法如下:
#include <shared_mutex>
template <class Mutex>
class shared_lock {
public:
bool try_lock(); // 尝试获取共享锁
...
};
- 返回值:若成功获取到共享锁,则返回
true;若锁不可用,返回false。
2. 完整示例代码
以下示例代码展示了如何使用 std::shared_lock<Mutex>::try_lock 在多线程环境中有效地管理对共享资源的访问。
#include <iostream>
#include <thread>
#include <shared_mutex>
#include <vector>
std::shared_mutex sh_mutex; // 定义共享互斥锁
std::vector<int> sharedData; // 共享数据容器
// 读取数据的函数
void readData() {
std::shared_lock<std::shared_mutex> lock(sh_mutex); // 获取共享锁
if (lock.try_lock()) { // 尝试获取共享锁
std::cout << "Thread " << std::this_thread::get_id()
<< " reading values: ";
for (const auto& val : sharedData) {
std::cout << val << " "; // 输出共享数据
}
std::cout << std::endl;
lock.unlock(); // 解锁
} else {
std::cout << "Thread " << std::this_thread::get_id()
<< " could not acquire shared lock." << std::endl;
}
}
// 写入数据的函数
void writeData(int value) {
std::unique_lock<std::shared_mutex> lock(sh_mutex); // 获取独占锁
sharedData.push_back(value); // 写入数据
std::cout << "Thread " << std::this_thread::get_id()
<< " wrote value: " << value << std::endl;
// mutex 将在 lock 的生命周期结束时自动解锁
}
int main() {
const int numWriters = 2; // 写线程数量
const int numReaders = 5; // 读线程数量
std::vector<std::thread> writers;
std::vector<std::thread> readers;
// 启动写线程
for (int i = 0; i < numWriters; ++i) {
writers.emplace_back(writeData, (i + 1) * 10); // 传入写入值
}
// 启动读线程
for (int i = 0; i < numReaders; ++i) {
readers.emplace_back(readData);
}
// 等待所有线程完成
for (auto& writer : writers) {
writer.join();
}
for (auto& reader : readers) {
reader.join();
}
return 0;
}
3. 代码解析
-
引入必要的头文件:
- 本程序使用
<iostream>、<thread>、<shared_mutex>和<vector>,为多线程编程和互斥量管理提供支持。
- 本程序使用
-
定义共享数据及互斥锁:
- 创建
std::shared_mutex sh_mutex;来保护对共享数据的访问,同时定义一个std::vector<int> sharedData;存储共享数据。
- 创建
-
读取函数:
- 在
readData函数中,使用std::shared_lock获取共享锁,如果能够在可用时成功抢锁,就读取并输出数据。如果锁不可用,则打印相应的提示。
- 在
-
写入函数:
writeData使用std::unique_lock管理对sh_mutex的独占锁定,以保证对共享资源数据的安全写入。
-
主函数中的线程管理:
- 在
main函数中,创建并启动多个写和读线程,最后join()等待各自线程完成。
- 在
4. 适用场景分析
4.1 读多写少的应用场合
在许多应用中,例如引用数据的查询和监控系统,读取数据比写入数据更为频繁,此时使用 std::shared_lock 可以提升性能。
4.2 实时数据获取与分析
在需要同时让多个线程读取共享数据的系统中,使用 try_lock 能有效减小请求队列堵塞,提高反应速度。
4.3 高并发环境中的缓存应用
针对多个用户请求相同数据(如缓存系统或数据库请求)的应用,使用共享锁的机制便于提升整体的程序 throughput(吞吐量)。
5. 总结
std::shared_lock<Mutex>::try_lock 是 C++22 并发库中一个非常重要的工具,允许多个线程灵活安全地共享访问资源。通过合适地使用这一特性,能够提高系统性能和用户体验,尤其是在读操作频繁、写操作较少的场景应用。在多线程开发中,掌握和灵活运用 try_lock 等特性,将为开发者提供更多的便利,促使高效且安全的并发编程能力不断提升。本文的讨论提供了对于 std::shared_lock 特性的全面了解,推动开发者充分利用现代 C++ 标准库中的同步工具。



没有回复内容