通知图标

欢迎访问津桥芝士站

mutex:std::shared_mutex::try_lock_shared

来自AI助手的总结
C++17的`std::shared_mutex::try_lock_shared`允许多个线程同时读取共享数据,适用于读多写少的场景,提高并发程序性能。

引入

在多线程编程领域,C++标准库为开发者提供了多种同步机制,以便于安全地管理共享资源。C++17引入了 <mutex> 头文件中的 std::shared_mutex,专为解决读多写少的场景而设计。这种互斥量允许多个线程同时读取共享数据,但在进行写操作时则需要独占访问。特别是,std::shared_mutex::try_lock_shared 方法提供了一种高效的方式,使线程能够尝试获得共享锁而不阻塞。理解这一功能,对于优化并发程序的性能具有重要意义。

1. 特性与函数介绍

1.1 特性

  • 非阻塞访问try_lock_shared 使线程能够尝试获取共享锁而不会被阻塞,当锁不可用时会立即返回,允许线程选择其他任务进行执行,提升响应性。
  • 精简的读访问:允许多个线程并发读取共享资源,而对于写操作,则要求独占锁定,确保数据一致性。
  • 优化执行流程:该方法适合于需要频繁读取、较少写入的数据结构,充分利用共享锁来提高性能。

1.2 函数语法

std::shared_mutex::try_lock_shared 的用法如下:

#include <mutex>
#include <chrono>

class shared_mutex : public mutex {
public:
    bool try_lock_shared(); // 尝试获取共享锁
    ...
};
  • 返回值:成功获取共享锁时返回 true,如果共享锁当前已被独占,则返回 false

2. 完整示例代码

下面的代码示例展示了如何使用 std::shared_mutex::try_lock_shared 在多线程环境中进行安全的读取操作。

#include <iostream>
#include <thread>
#include <shared_mutex>
#include <vector>
#include <chrono>

std::shared_mutex smtx; // 共享互斥锁
std::vector<int> sharedData; // 共享数据

// 读取数据的函数
void readData() {
    if (smtx.try_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(); // 释放共享锁
    } else {
        std::cout << "Thread " << std::this_thread::get_id() << " could not acquire shared lock." << std::endl;
    }
}

// 写入数据的函数
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 = 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);
    }

    // 启动读线程
    for (int i = 0; i < numReaders; ++i) {
        readers.emplace_back(readData);
        
        // 为了可见性,稍微延迟调用
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }

    // 等待所有线程完成
    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 smtx;,为共享数据提供线程安全的访问,同时定义一个共享的整型向量 std::vector<int> sharedData; 作为多个线程间的共享数据容器。
  3. 定义读取函数

    • readData 函数中调用 try_lock_shared() 尝试申请共享锁,如果成功,则读取共享数据并输出;失败则输出提示信息。
  4. 定义写入函数

    • writeData 函数中请求独占锁(使用 lock())以添加新数据到共享容器,并在完成后释放锁。
  5. 主函数中的线程管理

    • 在 main 函数多条线程被创建,分别执行 writeData 和 readData。其中,读取线程有意识地延迟调用,从而模拟高竞争环境。

4. 适用场景分析

4.1 频繁读取的应用场景

在读操作远多于写操作的场景中,如缓存或配置设置的读取,可以大大提高通过 try_lock_shared 获取的非阻塞方式的性能。

4.2 统计信息收集

在需要并发访问统计数据或者数据库状态时,多个线程同时获取共享锁进行读取,可顺利平衡并行处理。

4.3 实时数据流处理

在实时数据采集系统中,允许多线程对共享数据流进行读取,但要求唯一的写入完成机制,以精准控制数据的实时性和共享。

5. 总结

std::shared_mutex::try_lock_shared 为 C++ 提供了一种高效的并发控制方案。它的独特之处在于允许多个线程同时读取共享数据,而又保持对写操作的独占性,这使得在实现伸缩性和高效性的多线程程序时十分重要。合理使用 try_lock_shared 不仅能提升系统性能,还能减少竞争造成的资源瓶颈,以帮助开发者在复杂的多线程环境中实现更流畅的操作和管理。因此,掌握这一概念,是精通现代 C++ 多线程设计的关键锁匙。

请登录后发表评论

    没有回复内容

正在唤醒异次元光景……