2017-09-05 177 views
0

沒有得到一個在線示例來生動地演示這一點。在http://en.cppreference.com/w/cpp/header/shared_mutex上看到一個例子說明了一個例子,但是 仍然不清楚。有人可以幫忙嗎?共享互斥和互斥之間的區別(爲什麼都存在於C++ 11併發中)?

+4

您應該查看[documentation](http://en.cppreference.com/w/cpp/thread/shared_mutex)而不是標題摘要(如鏈接所示)。順便說一句,這是C++ 17而不是C++ 11。最接近的是C++ 14,它是'std :: shared_timed_mutex'。儘管如此,你有沒有聽說過[讀者 - 作家鎖定](https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock)? – WhiZTiM

回答

2

「共享互斥鎖通常用於多個讀者可以同時訪問同一資源而不引起數據競爭的情況,但只有一個作者可以這樣做。」

cppreference.com

當你需要讀取/寫入器鎖這是有用的:https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock

+0

是的,我只有線程可以同時讀取數據嗎?爲什麼讀者需要鎖?只有修改需要鎖定才能使底層的數據結構不被破壞? –

+0

@AnandKulkarni讀者需要鎖定,否則他們可能會讀取數據,而另一個線程正在寫入相同的數據。這是爲了防止數據競爭。通過讀取/寫入器鎖定,多個讀取器可以同時訪問數據。 – 0xBADF00

0

通過使用正常互斥的,你能保證某種關鍵資源的獨佔訪問 - 而不是其他。共享互斥通過允許訪問的兩級延伸此功能:共享和獨佔如下:

  • 獨佔訪問防止任何其它線程獲取該互斥,正如與正常的互斥。其他線程是否嘗試獲取共享或獨佔訪問權限並不重要。
  • 共享訪問允許多個線程獲取互斥量,但是所有的只能在共享模式下使用。直到所有先前的共享持有者已經返回互斥量爲止,纔會授予獨佔訪問權限(通常,只要獨佔請求正在等待,新共享對象在之後排隊等待授予)。

一個典型的場景是數據庫:多個線程同時讀取一個數據和同一個數據並不重要。但修改數據庫至關重要 - 如果某個線程正在讀取數據,而另一個線程正在寫入數據,則可能會收到不一致的數據。所以所有的閱讀必須完成才能書寫,新的閱讀必須等到寫作完成。寫入後,可能會再次同時發生進一步的讀取。

編輯:旁註:

爲什麼讀者需要的鎖?

這是爲了防止作者在讀取過程中獲取鎖而發生。此外,它還可以防止新讀者在專門持有鎖的情況下獲得鎖。

+0

非常清楚的理解,我們不希望讀者在修改正在發生時讀取陳舊的數據,反之亦然,因爲目前正在進行讀取,所以我們不希望作者開始進行更改以保持數據一致 –

0

共享互斥鎖有兩個訪問級別'shared'和'exclusive'。 多個線程可以獲得共享訪問權限,但只有一個可以擁有「獨佔」訪問權限(包括沒有共享訪問權限)。

常見的情況是讀/寫鎖。回想一下Data Race只能在兩個線程訪問相同的數據時發生其中至少有一個是寫

利用這些數據可能會被許多讀者讀取,但是當作者需要訪問時,他們必須獲得數據的獨佔訪問權。

下面是一個示例(稍後從示例http://en.cppreference.com/w/cpp/thread/shared_mutex稍微改編)。

#include <iostream> 
#include <mutex> // For std::unique_lock 
#include <shared_mutex> 
#include <thread> 


std::mutex cout_mutex; 
void log(const std::string& msg){ 
    std::lock_guard guard(cout_mutex); 
    std::cout << msg << std::endl; 
} 

class ThreadSafeCounter { 
public: 
    ThreadSafeCounter() = default; 

    // Multiple threads/readers can read the counter's value at the same time. 
    unsigned int get() const { 
    std::shared_lock lock(mutex_);//NB: std::shared_lock will shared_lock() the mutex. 
    log("get()-begin"); 
    std::this_thread::sleep_for(std::chrono::milliseconds(500)); 
    auto result=value_; 
    log("get()-end"); 
    return result; 
    } 

    // Only one thread/writer can increment/write the counter's value. 
    void increment() { 
    std::unique_lock lock(mutex_); 
    value_++; 
    } 

    // Only one thread/writer can reset/write the counter's value. 
    void reset() { 
    std::unique_lock lock(mutex_); 
    value_ = 0; 
    } 

private: 
    mutable std::shared_mutex mutex_; 
    unsigned int value_ = 0; 
}; 

int main() { 
    ThreadSafeCounter counter; 

    auto increment_and_print = [&counter]() { 
    for (int i = 0; i < 3; i++) { 
     counter.increment(); 
     auto ctr=counter.get(); 
     { 
      std::lock_guard guard(cout_mutex); 
      std::cout << std::this_thread::get_id() << ' ' << ctr << '\n'; 
     } 
    } 
    }; 

    std::thread thread1(increment_and_print); 
    std::thread thread2(increment_and_print); 
    std::thread thread3(increment_and_print); 

    thread1.join(); 
    thread2.join(); 
    thread3.join(); 
} 

可能的部分輸出:

get()-begin 
get()-begin 
get()-end 
140361363867392 2 
get()-end 
140361372260096 2 
get()-begin 
get()-end 
140361355474688 3 
//Etc... 

通知如何兩個get()-begin()返回顯示,兩個線程的讀取期間保持共享鎖。