C++ 并发编程,std::unique_lock与std::lock_guard区别示例

虾米姐 阅读:935 2020-10-15 11:27:40 评论:0

背景

平时看代码时,也会使用到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; 
} 
标签:C++
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

关注我们

一个IT知识分享的公众号