淺談C++11中的幾種鎖

互斥鎖(mutex)

可以避免多個線程在某一時刻同時操作一個共享資源,標準C++庫提供瞭std::unique_lock類模板,實現瞭互斥鎖的RAII慣用語法:
eg:

std::unique_lock<std::mutex> lk(mtx_sync_);

條件鎖(condition_variable)

條件鎖就是所謂的條件變量,某一個線程因為某個條件未滿足時可以使用條件變量使該程序處於阻塞狀態。一旦條件滿足瞭,即可喚醒該線程(常和互斥鎖配合使用),喚醒後,需要檢查變量,避免虛假喚醒。
eg:

線程1:

// wait ack
{
    std::unique_lock<std::mutex> lk(mtx_sync_);
    if (!cv_sync_.wait_for(lk, 1000ms, [this](){return sync_; })) // wait for 1s
    {
        // wait failed
        printf("wait for notify timeout [%d].\n", cnt);
        return false;
    }
    else
    {
        return true;
    }
}

線程2:

{
    std::unique_lock<std::mutex> lk(mtx_sync_);
    sync_ = true;
}
// 通知前解鎖,可以避免喚醒線程後由於互斥鎖的關系又進入瞭阻塞階段
cv_sync_.notify_one();

自旋鎖(不推薦使用)

自旋鎖是一種基礎的同步原語,用於保障對共享數據的互斥訪問。與互斥鎖的相比,在獲取鎖失敗的時候不會使得線程阻塞而是一直自旋嘗試獲取鎖。當線程等待自旋鎖的時候,CPU不能做其他事情,而是一直處於輪詢忙等的狀態。自旋鎖主要適用於被持有時間短,線程不希望在重新調度上花過多時間的情況。實際上許多其他類型的鎖在底層使用瞭自旋鎖實現,例如多數互斥鎖在試圖獲取鎖的時候會先自旋一小段時間,然後才會休眠。如果在持鎖時間很長的場景下使用自旋鎖,則會導致CPU在這個線程的時間片用盡之前一直消耗在無意義的忙等上,造成計算資源的浪費。

// 用戶空間用 atomic_flag 實現自旋互斥
#include <thread>
#include <vector>
#include <iostream>
#include <atomic>
 
std::atomic_flag lock = ATOMIC_FLAG_INIT;
 
void f(int n)
{
    for (int cnt = 0; cnt < 100; ++cnt) {
        while (lock.test_and_set(std::memory_order_acquire))  // 獲得鎖
             ; // 自旋
        std::cout << "Output from thread " << n << '\n';
        lock.clear(std::memory_order_release);               // 釋放鎖
    }
}
 
int main()
{
    std::vector<std::thread> v;
    for (int n = 0; n < 10; ++n) {
        v.emplace_back(f, n);
    }
    for (auto& t : v) {
        t.join();
    }
}

遞歸鎖(recursive_mutex)

recursive_mutex 類是同步原語,能用於保護共享數據免受從個多線程同時訪問。

recursive_mutex 提供排他性遞歸所有權語義:

  • 調用方線程在從它成功調用 lock 或 try_lock 開始的時期裡占有 recursive_mutex 。此時期間,線程可以進行對 lock 或 try_lock 的附加調用。所有權的時期在線程調用 unlock 匹配次數時結束。
  • 線程占有 recursive_mutex 時,若其他所有線程試圖要求 recursive_mutex 的所有權,則它們將阻塞(對於調用 lock )或收到 false 返回值(對於調用 try_lock )。
  • 可鎖定 recursive_mutex 次數的最大值是未指定的,但抵達該數後,對 lock 的調用將拋出 std::system_error 而對 try_lock 的調用將返回 false 。
  • 若 recursive_mutex 在仍為某線程占有時被銷毀,則程序行為未定義。 recursive_mutex 類滿足互斥 (Mutex) 和標準佈局類型 (StandardLayoutType) 的所有要求。

 到此這篇關於淺談C++11中的幾種鎖的文章就介紹到這瞭,更多相關C++11 鎖內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: