C++ 並發編程,std::unique_lock與std::lock_guard區別示例


背景

平時看代碼時,也會使用到std::lock_guard,但是std::unique_lock用的比較少。在看並發編程,這里總結一下。方便后續使用。

std::unique_lock也可以提供自動加鎖、解鎖功能,比std::lock_guard更加靈活。

std::lock_guard

std::lock_guard是RAII模板類的簡單實現,功能簡單。

1.std::lock_guard 在構造函數中進行加鎖,析構函數中進行解鎖。
2.鎖在多線程編程中,使用較多,因此c++11提供了lock_guard模板類;在實際編程中,我們也可以根據自己的場景編寫resource_guard RAII類,避免忘掉釋放資源。

下面是一個使用std::lock_guard的代碼例子,1+2+ .. + 100的多線程實現,每個num只能由一個線程處理。:

#include <thread>
#include <mutex>
#include <vector>
#include <iostream>
#include <algorithm>

std::mutex my_lock;

void add(int &num, int &sum){
    while(true){
        std::lock_guard<std::mutex> lock(my_lock);  
        if (num < 100){ //運行條件
            num += 1;
            sum += num;
        }   
        else {  //退出條件
            break;
        }   
    }   
}

int main(){
    int sum = 0;
    int num = 0;
    std::vector<std::thread> ver;   //保存線程的vector
    for(int i = 0; i < 20; ++i){
        std::thread t = std::thread(add, std::ref(num), std::ref(sum));
        ver.emplace_back(std::move(t)); //保存線程
    }   

    std::for_each(ver.begin(), ver.end(), std::mem_fn(&std::thread::join)); //join
    std::cout << sum << std::endl;
}

std::unique_lock

類 unique_lock 是通用互斥包裝器,允許延遲鎖定、鎖定的有時限嘗試、遞歸鎖定、所有權轉移和與條件變量一同使用
unique_lock比lock_guard使用更加靈活,功能更加強大。
使用unique_lock需要付出更多的時間、性能成本。

下面是try_lock的使用例子。

#include <iostream>       // std::cout
#include <thread>         // std::thread
#include <mutex>          // std::mutex, std::unique_lock
#include <vector>

std::mutex mtx;           // mutex for critical section
std::once_flag flag;

void print_block (int n, char c) {
    //unique_lock有多組構造函數, 這里std::defer_lock不設置鎖狀態
    std::unique_lock<std::mutex> my_lock (mtx, std::defer_lock);
    //嘗試加鎖, 如果加鎖成功則執行
    //(適合定時執行一個job的場景, 一個線程執行就可以, 可以用更新時間戳輔助)
    if(my_lock.try_lock()){
        for (int i=0; i<n; ++i)
            std::cout << c;
        std::cout << '\n';
    }
}

void run_one(int &n){
    std::call_once(flag, [&n]{n=n+1;}); //只執行一次, 適合延遲加載; 多線程static變量情況
}

int main () {
    std::vector<std::thread> ver;
    int num = 0;
    for (auto i = 0; i < 10; ++i){
        ver.emplace_back(print_block,50,'*');
        ver.emplace_back(run_one, std::ref(num));
    }

    for (auto &t : ver){
        t.join();
    }
    std::cout << num << std::endl;
    return 0;
}

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM