当前位置: 首页 > news >正文

【多线程】c++11多线程编程(五)——unique_lock和lock_guard

互斥锁保证了线程间的同步,但是却将并行操作变成了串行操作,这对性能有很大的影响,所以我们要尽可能的减小锁定的区域,也就是使用细粒度锁

这一点lock_guard做的不好,不够灵活,lock_guard只能保证在析构的时候执行解锁操作,lock_guard本身并没有提供加锁和解锁的接口,但是有些时候会有这种需求。看下面的例子。

class LogFile {
    std::mutex _mu;
    ofstream f;
public:
    LogFile() {
        f.open("log.txt");
    }
    ~LogFile() {
        f.close();
    }
    void shared_print(string msg, int id) {
        {
            std::lock_guard<std::mutex> guard(_mu);
            //do something 1
        }
        //do something 2
        {
            std::lock_guard<std::mutex> guard(_mu);
            // do something 3
            f << msg << id << endl;
            cout << msg << id << endl;
        }
    }

};

上面的代码中,一个函数内部有两段代码需要进行保护,这个时候使用lock_guard就需要创建两个局部对象来管理同一个互斥锁(其实也可以只创建一个,但是锁的力度太大,效率不行),修改方法是使用unique_lock。它提供了lock()unlock()接口,能记录现在处于上锁还是没上锁状态,在析构的时候,会根据当前状态来决定是否要进行解锁(lock_guard就一定会解锁)。上面的代码修改如下:

class LogFile {
    std::mutex _mu;
    ofstream f;
public:
    LogFile() {
        f.open("log.txt");
    }
    ~LogFile() {
        f.close();
    }
    void shared_print(string msg, int id) {

        std::unique_lock<std::mutex> guard(_mu);
        //do something 1
        guard.unlock(); //临时解锁

        //do something 2

        guard.lock(); //继续上锁
        // do something 3
        f << msg << id << endl;
        cout << msg << id << endl;
        // 结束时析构guard会临时解锁
        // 这句话可要可不要,不写,析构的时候也会自动执行
        // guard.ulock();
    }

};

上面的代码可以看到,在无需加锁的操作时,可以先临时释放锁,然后需要继续保护的时候,可以继续上锁,这样就无需重复的实例化lock_guard对象,还能减少锁的区域。同样,可以使用std::defer_lock设置初始化的时候不进行默认的上锁操作:

void shared_print(string msg, int id) {
    std::unique_lock<std::mutex> guard(_mu, std::defer_lock);
    //do something 1

    guard.lock();
    // do something protected
    guard.unlock(); //临时解锁

    //do something 2

    guard.lock(); //继续上锁
    // do something 3
    f << msg << id << endl;
    cout << msg << id << endl;
    // 结束时析构guard会临时解锁
}

这样使用起来就比lock_guard更加灵活!然后这也是有代价的,因为它内部需要维护锁的状态,所以效率要比lock_guard低一点,在lock_guard能解决问题的时候,就是用lock_guard,反之,使用unique_lock

后面在学习条件变量的时候,还会有unique_lock的用武之地。

另外,请注意,unique_locklock_guard都不能复制,lock_guard不能移动,但是unique_lock可以!

// unique_lock 可以移动,不能复制
std::unique_lock<std::mutex> guard1(_mu);
std::unique_lock<std::mutex> guard2 = guard1;  // error
std::unique_lock<std::mutex> guard2 = std::move(guard1); // ok

// lock_guard 不能移动,不能复制
std::lock_guard<std::mutex> guard1(_mu);
std::lock_guard<std::mutex> guard2 = guard1;  // error
std::lock_guard<std::mutex> guard2 = std::move(guard1); // error

参考

  1. C++并发编程实战
  2. C++ Threading #5: Unique Lock and Lazy Initialization


作者:StormZhu
链接:https://www.jianshu.com/p/34d219380d90
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

相关文章:

  • 【C/C++】内存和字符操作整理
  • 【知识】如何高效地在github上找开源项目学习?
  • 【mySQL】比explain更加详细的分析计划:Query Profiler
  • 【mySQL】mysql是行级锁还是表级锁
  • 【mySQL】提升mysql性能的关键参数之innodb_buffer_pool_size、innodb_buffer_pool_instances
  • 【mySQL】数据库优化 方案
  • 【interview】遇到的困难
  • 【排序】常见排序算法及其时间复杂度
  • 【mySQL】数据库[配置]优化 方案(MySQL并行写入、查询性能调优(多核CPU))
  • 【C++11】C++ 中using 的使用
  • 【linux】进程间通信-消息队列
  • 【C++】C++ STL stack 用法
  • 【C++】什么是函数对象和函数对象的用处
  • 【C++】STL标准容器的排序操作和选择合适的排序算法
  • 【C++】程序猿c++(11) 字符串比较误区总结
  • [LeetCode] Wiggle Sort
  • django开发-定时任务的使用
  • Essential Studio for ASP.NET Web Forms 2017 v2,新增自定义树形网格工具栏
  • Java程序员幽默爆笑锦集
  • jQuery(一)
  • js中forEach回调同异步问题
  • Laravel深入学习6 - 应用体系结构:解耦事件处理器
  • mysql 5.6 原生Online DDL解析
  • python 装饰器(一)
  • Unix命令
  • Web Storage相关
  • 爬虫模拟登陆 SegmentFault
  • 让你的分享飞起来——极光推出社会化分享组件
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 如何正确配置 Ubuntu 14.04 服务器?
  • 入职第二天:使用koa搭建node server是种怎样的体验
  • 深度学习入门:10门免费线上课程推荐
  • 时间复杂度与空间复杂度分析
  • Oracle Portal 11g Diagnostics using Remote Diagnostic Agent (RDA) [ID 1059805.
  • 长三角G60科创走廊智能驾驶产业联盟揭牌成立,近80家企业助力智能驾驶行业发展 ...
  • 如何在招聘中考核.NET架构师
  • ​一些不规范的GTID使用场景
  • #Linux(make工具和makefile文件以及makefile语法)
  • #stm32驱动外设模块总结w5500模块
  • (2.2w字)前端单元测试之Jest详解篇
  • (3)Dubbo启动时qos-server can not bind localhost22222错误解决
  • (Bean工厂的后处理器入门)学习Spring的第七天
  • (编译到47%失败)to be deleted
  • (初研) Sentence-embedding fine-tune notebook
  • (二)学习JVM —— 垃圾回收机制
  • (附源码)springboot 房产中介系统 毕业设计 312341
  • (剑指Offer)面试题34:丑数
  • (完整代码)R语言中利用SVM-RFE机器学习算法筛选关键因子
  • (五) 一起学 Unix 环境高级编程 (APUE) 之 进程环境
  • (已解决)报错:Could not load the Qt platform plugin “xcb“
  • (原创)Stanford Machine Learning (by Andrew NG) --- (week 9) Anomaly DetectionRecommender Systems...
  • .gitignore文件—git忽略文件
  • .net framwork4.6操作MySQL报错Character set ‘utf8mb3‘ is not supported 解决方法
  • .NET简谈互操作(五:基础知识之Dynamic平台调用)
  • @Documented注解的作用