zoukankan      html  css  js  c++  java
  • C++ Concurrency in Action 读书笔记

    一、锁的根本目标:维持不变式

      类一般都维持一些不变式,就是关于一个数据结构的总是为真的陈述(好像一般都是指内部变量的意义)。比如链表的两个不变式是,一个节点的next指针总是指向下一个节点,链表的number成员变量总是指明了节点总数。这些不变式总会在链表变动时被破坏,比如向链表插入一个节点时,总会有一个时刻,某个节点的next指针指向的不是它真正的下一个节点,number成员也会有一个时刻表达的不是节点真正的总数。如果在这些时刻有其它线程来操作这些不变式被破坏的地方,那就会引发竞争条件(最终的结果依赖于两个线程的执行次序)。所以锁的存在就是为了对外部保持不变式,不让外部接触到不变式暂时被破坏的地方。

    二、单个锁的用法和注意事项

      一个锁一般都是为了保护一份共享数据,只要有一个对数据的操作会破坏不变式,那么所有对这个数据的访问都要锁上这个锁,以防接触到被破坏的状态。由于这个锁和数据联系紧密,一般会封装在一个类里。在使用时,一般在成员方法开头用 std::lock_guard 或者 std::unique_lock 锁起来,而不是直接裸调 std::mutex::lock ,因为前两者可以使用RAII技术恰当地解锁。而且即使这个锁之前已经锁上了,或者稍后才要上锁,也最好将锁委托给 std::lock_guard 和 std::unique_lock 来解锁。

      一个特别值得注意的问题是,千万不要把共享数据的指针或者引用传到锁的范围之外,比如用成员方法的参数或者返回值把它传到外面去,那显然数据就不再受锁的保护了。其它的危险方式还有:把共享数据的指针或者引用,存到外部可见的内存区,或者传递到用户提供的回调函数中(因为回调函数可能会把这个指针或引用存起来)。书中斜体字原文为:“Don't pass pointers and references to protected data outside the scope of the lock, whether by returning them from a function, storing them in externally visible memory, or passing them as arguments to user-supplied functions.

      即使这样,还是有潜在的危险:锁一般只能保证一个成员方法内部的正确性,如果两个成员方法之间有逻辑上的依赖关系,那锁就无能为力了。比如仅当 std::stack::empty() 返回 false 时,才能调用 std::stack::pop() ,虽然这两个方法内部都正确加了锁,但如果这个两个调用之间插入了另一个线程的 std::stack::pop(),显然就可能出问题。至于 std::stack 为什么这么设计,以及如何解决这个问题,因为有些复杂,这里不细说,详见书中讲述。这里简单总结解决方法:1.在外面构造好存放结果的变量,作为引用或指针传给 pop(result);2.pop() 返回shared_ptr。

    三、多个锁引起的问题:死锁

      死锁的四个必要条件:互斥(一个资源每次只能被一个线程使用)、请求和保持、不剥夺、环路等待。

      C++ 11提供的 std::lock() 可以一次给多个锁上锁,方便多了,但是需要同时拿到所有锁的对象(或指针引用)才可以,如果锁分散在多个模块中(比如用户回调函数中)就比较麻烦了。避免的方法有:

      1. 持有一个锁时就不再请求另一个锁;
      2. 持有锁时避免调用回调函数;
      3. 如果一定要调回调函数的话,那就安排一个固定的锁次序;
      4. 设计锁层次

  • 相关阅读:
    hdu 4521 小明系列问题——小明序列(线段树 or DP)
    hdu 1115 Lifting the Stone
    hdu 5476 Explore Track of Point(2015上海网络赛)
    Codeforces 527C Glass Carving
    hdu 4414 Finding crosses
    LA 5135 Mining Your Own Business
    uva 11324 The Largest Clique
    hdu 4288 Coder
    PowerShell随笔3 ---别名
    PowerShell随笔2---初始命令
  • 原文地址:https://www.cnblogs.com/yding9/p/3651567.html
Copyright © 2011-2022 走看看