通知图标

欢迎访问津桥芝士站

shared_mutex:std::shared_lock::try_lock

来自AI助手的总结
C++17 的 `std::shared_lock::try_lock` 允许多个线程并发读取共享资源,同时在写入时确保独占访问,提高了多线程编程的性能和灵活性。

引入

在多线程编程中,合理有效地管理对共享资源的访问,对于维护程序的稳定性及安全性至关重要。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. 代码解析

  1. 引入必要的头文件

    • 本程序使用 <iostream><thread><shared_mutex> 和 <vector>,为多线程编程和互斥量管理提供支持。
  2. 定义共享数据及互斥锁

    • 创建 std::shared_mutex sh_mutex; 来保护对共享数据的访问,同时定义一个 std::vector<int> sharedData; 存储共享数据。
  3. 读取函数

    • 在 readData 函数中,使用 std::shared_lock 获取共享锁,如果能够在可用时成功抢锁,就读取并输出数据。如果锁不可用,则打印相应的提示。
  4. 写入函数

    • writeData 使用 std::unique_lock 管理对 sh_mutex 的独占锁定,以保证对共享资源数据的安全写入。
  5. 主函数中的线程管理

    • 在 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++ 标准库中的同步工具。

请登录后发表评论

    没有回复内容

正在唤醒异次元光景……