美文网首页程序员
C++ 并发编程学习(七)

C++ 并发编程学习(七)

作者: rmrfany | 来源:发表于2018-12-29 19:44 被阅读0次

共享数据带来的问题

  双链表中每个节点都有一个指针指向列表中下一个节点,还有一个指针指向前一个节点。其中不变量就是节点A中指向“下一个”节点B的指针,还有前向指针。为了从列表中删除一个节点,其两边节点的指针都需要更新。当其中一边更新完成时,不变量就被破坏了,直到另一边也完成更新;在两边都完成更新后,不变量就又稳定了。从一个列表中删除一个节点的步骤如下

  1. 找到要删除的节点N
  2. 更新前一个节点指向N的指针,让这个指针指向N的下一个节点
  3. 更新后一个节点指向N的指针,让这个指正指向N的前一个节点
  4. 删除节点N
双向链表.PNG

  图中b和c在相同的方向上指向和原来已经不一致了,这就破坏了不变量。线程间潜在问题就是修改共享数据,致使不变量遭到破坏。当不做些事来确保在这个过程中不会有其他线程进行访问的话,可能就有线程访问到刚刚删除一边的节点;这样的话,线程就读取到要删除节点的数据(因为只有一边的连接被修改,如图(b),所以不变量就被破坏。破坏不变量的后果是多样,当其他线程按从左往右的顺序来访问列表时,它将跳过被删除的节点。在一方面,如有第二个线程尝试删除图中右边的节点,那么可能会让数据结构产生永久性的损坏,使程序崩溃。无论结果如何,都是并行代码常见错误:条件竞争。

一. 条件竞争

  并发中竞争条件的形成,取决于一个以上线程的相对执行顺序,每个线程都抢着完成自己的任务。大多数情况下,即使改变执行顺序,也是良性竞争,其结果可以接受。例如,有两个线程同时向一个处理队列中添加任务,因为系统提供的不变量保持不变,所以谁先谁后都不会有什么影响。当不变量遭到破坏时,才会产生条件竞争,比如双向链表删除链表中间的某一项。并发中对数据的条件竞争通常表示为恶性条件竞争,我们对不产生问题的良性条件竞争不感兴趣。 C++ 标准中也定义了数据竞争这个术语,一种特殊的条件竞争:并发的去修改一个独立对象,数据竞争是(可怕的)未定义行为的起因。
  恶性条件竞争通常发生于完成对多于一个的数据块的修改时,因为操作要访问两个独立的数据块,独立的指令将会对数据块将进行修改,并且其中一个线程可能正在进行时,另一个线程就对数据块进行了访问。因为出现的概率太低,条件竞争很难查找,也很难复现。

二. 避免恶性条件竞争

  解决恶性条件竞争,最简单的办法就是对数据结构采用某种保护机制,确保只有进行修改的线程才能看到不变量被破坏时的中间状态。从其他访问线程的角度来看,修改不是已经完成了,就是还没开始。
  另一个选择是对数据结构和不变量的设计进行修改,修改完的结构必须能完成一系列不可分割的变化,也就是保证每个不变量保持稳定的状态,这就是所谓的无锁编程。不过,这种方式很难得到正确的结果。
  另一种处理条件竞争的方式是,使用事务的方式去处理数据结构的更新(这里的"处理"就如同对数据库进行更新一样)。所需的一些数据和读取都存储在事务日志中,然后将之前的操作合为一步,再进行提交。当数据结构被另一个线程修改后,或处理已经重启的情况下,提交就会无法进行,这称作为“软件事务内存”。理论研究中,这是一个很热门的研究领域。
  保护共享数据结构的最基本的方式,是使用C++标准库提供的互斥量。

相关文章

  • C++ 并发编程学习(七)

    共享数据带来的问题   双链表中每个节点都有一个指针指向列表中下一个节点,还有一个指针指向前一个节点。其中不变量就...

  • C/C++并发编程(1)—— 并发/并行、多线程内存模型

    最近看了《七周七并发模型》[1],对自己熟悉的C/C++并发编程有了很多新的思考。在Google上搜索“C C++...

  • C++ 并发编程学习(六)

    识别线程 一. 获得线程标识(std::thread::id ) std::thread 对象的成员函数 get_...

  • C++ 并发编程学习(九)

    保护共享数据的替代设施 一. std::once_flag 和 std::call_once 二. 一个 std:...

  • C++ 并发编程学习(一)

    一. 任务切换与硬件并发 以前,大多数计算机只有一个处理器,具有单个处理单元(processing unit)或...

  • C++ 并发编程学习(八)

    使用互斥量保护共享数据   互斥量是 C++ 中一种最通用的数据保护机制,但它不是“银弹”;精心组织代码来保护正确...

  • C++ 并发编程学习(二)

    线程管理的基础 一. 启用线程 线程的使用需要头文件 ,以及在编译的时候需要使用 -lpthread;起线程时初始...

  • C++ 并发编程学习(四)

    转移线程所有权 一. std::thread 实例之间(t1,t2和t3)转移所有权   当显式使用 std::...

  • C++ 并发编程学习(三)

    向线程函数传递参数 一. 传参const char*   函数f需要一个 std::string 对象作为第二个参...

  • C++ 并发编程学习(五)

    运行时决定线程数量 一. 原生并行版的 std::accumulate   std::thread::hardwa...

网友评论

    本文标题:C++ 并发编程学习(七)

    本文链接:https://www.haomeiwen.com/subject/lafzkqtx.html