zoukankan      html  css  js  c++  java
  • 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 << '
    ';
        }
    }
    
    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;
    }
    

    参考

  • 相关阅读:
    总结
    PHP的重载-使用魔术方法实现
    用PHP实现一些常见的排序算法
    MySQL分组聚合group_concat + substr_index
    各种链接地址
    在Linux服务器上使用rz命令上传文件时时老报:Segmentation Fault,上传失败
    新安装的windows 10无法更新报0x80240fff错误的解决方案
    通过SSH key获取GitHub上项目,导入到IDEA中
    解压.zip,.tar.gz文件到指定目录,重命名文件
    byte字节数组的压缩
  • 原文地址:https://www.cnblogs.com/xudong-bupt/p/9194394.html
Copyright © 2011-2022 走看看