c++中的讀寫鎖

牛马chen發表於2024-10-06

讀寫鎖是一種特殊的鎖機制,允許多個執行緒同時讀取共享資料,但在寫入共享資料時,只有一個執行緒可以進行寫操作,其他執行緒必須等待。

這種機制對於讀多寫少的場景非常有效,可以提高併發效能。以下是透過 shared_lockunique_lockshared_mutexmutex 的解釋來說明讀寫鎖的實現和應用。

1. 基本概念

  • 讀鎖(Shared Lock)

    • 使用 shared_lock 加鎖,允許多個執行緒同時持有讀鎖,這樣它們可以併發地讀取共享資料。
    • 在持有讀鎖的情況下,其他執行緒仍然可以獲取讀鎖,但無法獲取寫鎖。
  • 寫鎖(Exclusive Lock)

    • 使用 unique_lock 加鎖,只有一個執行緒可以持有寫鎖。持有寫鎖的執行緒在寫入資料時,其他執行緒無法獲取任何型別的鎖(無論是讀鎖還是寫鎖)。
    • 寫鎖的目的在於保證資料的安全性和一致性。

2. shared_mutexmutex

  • shared_mutex

    • 是 C++14 引入的一個互斥體型別,專門用於支援讀寫鎖
      -** 它支援共享鎖(透過 shared_lock)和獨佔鎖(透過 unique_lock)**。透過這種方式,多個執行緒可以安全地讀取資料,而在寫入資料時,可以保證只有一個執行緒在寫。
  • mutex

    • 是最基本的互斥體,提供了互斥訪問共享資源的功能。
    • 使用 mutex 時,如果一個執行緒持有鎖,其他執行緒都無法訪問受保護的資源。

3. 示例程式碼

以下是一個示例,展示瞭如何使用 shared_mutexshared_lockunique_lock 實現一個簡單的讀寫鎖:

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

class SharedData {
private:
    int data;
    mutable std::shared_mutex mutex;

public:
    SharedData() : data(0) {}

    // 讀操作
    int read() const {
        std::shared_lock<std::shared_mutex> lock(mutex); // 共享鎖
        return data;
    }

    // 寫操作
    void write(int value) {
        std::unique_lock<std::shared_mutex> lock(mutex); // 獨佔鎖
        data = value;
    }
};

// 讀執行緒函式
void reader(SharedData& shared_data, int id) {
    for (int i = 0; i < 5; ++i) {
        std::cout << "Reader " << id << " reads: " << shared_data.read() << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

// 寫執行緒函式
void writer(SharedData& shared_data, int value) {
    for (int i = 0; i < 5; ++i) {
        shared_data.write(value);
        std::cout << "Writer writes: " << value << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(300));
        value++; // 增加寫入值
    }
}

int main() {
    SharedData shared_data;

    // 建立讀執行緒
    std::vector<std::thread> readers;
    for (int i = 0; i < 3; ++i) {
        readers.emplace_back(reader, std::ref(shared_data), i);
    }

    // 建立寫執行緒
    std::thread writer_thread(writer, std::ref(shared_data), 0);

    // 等待執行緒完成
    for (auto& r : readers) {
        r.join();
    }
    writer_thread.join();

    return 0;
}

4. 解釋

  • 共享讀取

    • read 方法中,使用 shared_lock 來加鎖。這允許多個執行緒同時讀取 data,因為它們不會阻塞彼此。
  • 獨佔寫入

    • write 方法中,使用 unique_lock 來加鎖。這保證了在寫入資料時,其他執行緒不能讀取或寫入。
  • 執行緒安全

    • 透過使用 shared_mutex,確保在讀取時允許併發訪問,而在寫入時則獨佔訪問,有效提高了程式的併發效能。

總結

讀寫鎖是提高讀多寫少場景下效能的有效機制。透過使用 shared_mutexshared_lockunique_lock,可以實現安全的併發訪問,確保資料的一致性和正確性。這種方式在多執行緒程式設計中是非常常見的,特別是在需要頻繁讀取而寫入相對較少的應用中。

相關文章