C++并发编程实战(读书笔记)——C++内存模型不好理解;无锁数据结构?但是等待不就是被锁住了吗??

C++11:原子交换函数compare_exchange_weak和compare_exchange_strong 初探 compare_exchange_weak和compare_exchange_strong则是著名的CAS(compare and set) 阅读详情

C++并发编程实战

基本线程管理[编辑]

  1. p18 RAII:~thread_guard:if(t.joinable())t.join();
  2. p29 std::this_thread::get_id()

在线程间共享数据[编辑]

  1. mutex
    1. p36 std::lock_guard<std::mutex> l(m); //RAII风格
    2. p45 std::lock可以用时锁住2个或更多的mutex?
    3. p46 让每个线程仅持有一个锁,--> 但是仍然有可能相互等待...
    4. p50 层次锁?
    5. p52 std::unique_lock??
  2. p57 臭名昭著的2次检查锁定模式:data race(~ C++内存模型)
    1. std::call_once(std::once_flag f, std::shared_ptr<T> res);
  3. p60 读写mutex:boost::shared_mutex
  4. p61 递归锁(略)

同步[编辑]

  1. std::condition_variable data_cond;
    1. data_cond.wait( lk, []{return !queue.empty()} );
    2. data_cond.notify_one(); //唤醒一个,注意,上面2句都需要在std::unique_lock的保护范围内(queue是共享变量)
  2. p68 threadsafe_queue?
  3. 使用future等待一次性事件
    1. std::future<T> result = std::async(doWork); //将在result.get()时阻塞
  4. std::packaged_task<T=Callable> -> get_future() //高层抽象
  5. std::promise*
    1. set_value / get_future
  6. std::shared_future*
  7. std::chrono::
    1. system_clock, steady_clock, high_resolution_clock
    2. duration
    3. time_point
  8. std::timed_mutex:try_lock_for / try_lock_until
  9. p91 基于future的parallel_quick_sort
  10. p92 spawn_task
    1. typedef std::result_of<F(A&&)>::type result_type; //?

C++内存模型和原子操作[编辑]

  1. std::atomic_flag f = ATOMIC_FLAG_INIT;
    1. lock: while(f.test_and_set(std::memory_order_acquire)); //可以运行时切换std::memory_order_*参数到底是个什么鬼??
    2. unlock: fl.clear(std::memory_order_release);
  2. 更通用的std::atomic<bool>
    1. b.compare_exchange_weak(expected_value, memory_order_acq_rel, memory_order_acquire); //?
  3. std::atomic<T*>上的操作
    1. p108 p.fetch_add(3, std::memory_order_release);
  4. std::atomic<UDT>
    1. UDT必须有平凡的拷贝赋值(且必须是编译器默认生成的,POD?)、必须是按位相等可比较的
  5. 原子操作函数*
  6. p114 happens-before和synchronizes_with
  7. p116 6种内存顺序:
    1. 代表了3种模型:
      1. 顺序一致(最容易理解的,但在多处理器但弱顺序机器上有性能问题)
      2. 非顺序一致:*
        1. ?唯一的要求是所有的线程对每个独立变量的修改顺序达成一致(“达成一致”指的是什么意思???)
      3. 松弛:原子类型上但操作不参与synchronizes_with关系,单线程中的同一个变量的操作仍然服从happens-before关系
      4. p124 获得-释放:靠,仍然有点费解
      5. 获取-释放顺序传递性同步*
      6. p130 memory_order_consume:数据依赖(?)
  8. p133 释放序列和synchronizes_with **
  9. 内存屏障
    1. p137 用原子操作排序非原子操作*

基于锁的并发数据结构[编辑]

  1. p162 设计一个细粒度的map数据结构
    1. RB-tree(std::map)从访问根节点开始,... 尽管线程沿着树往下移动的时候会释放这个锁 ...
    2. 已排序数组
    3. hashmap:可以在每个桶上有一个独立的锁
  2. p165 编写一个使用锁的线程安全链表
    1. 基本思想是每个节点使用一个mutex(细粒度锁)... ?如果要修改相邻的2个节点,需要同时上锁吧?
    2. 可以参考Linux Kernel里的list实现...

设计无锁并发数据结构[编辑]

  1. p174 无锁的线程安全栈*
    1. 不是无等待的!(线程死循环忙等不就相当于被“锁住”了吗?)
    2. p178 管理内存(防止泄露):你想释放一个节点,但必须确保没有别的线程引用时才能这么做,... 这从根本上意味着需要为节点写一个专用GC
    3. p182 用风险指针(hazard pointers)检测不能回收的节点 *
    4. p189 使用引用计数检测节点 *
    5. p194 将内存模型应用至无锁栈 *
  2. p198 无锁队列
  3. 编写无锁数据结构的准则
    1. p210 使用std::memory_order_seq_cst
    2. 使用无锁内存回收模式
    3. 当心ABA问题
    4. 识别忙于等待的循环及辅助其他线程

设计并发代码[编辑]

  1. p219 以任务类型划分工作
  2. p221 划分线程间的任务队列(管道)
  3. 影响性能的因素
    1. p223 数据竞争和缓存乒乓
    2. 假共享(CPU的片内cache line)
  4. 额外考虑
    1. p230 并行算法中的异常安全 *
  5. 在实践中设计并发代码:STL算法的并行实现 **
    1. std::for_each
    2. std::find
    3. std::partial_sum

高级线程管理[编辑]

  1. 线程池
  2. 中断线程(这里的思想似乎来自于Java interrupt()?)

多线程应用的测试与调试[编辑]

  1. 不必要的阻塞:死锁、活锁、IO阻塞
  2. 竞争条件
  3. 多线程测试
    1. ps:Google Android上的Address Sanitizer (ASAN)工具?

附录A C++部分语言特性简明参考[编辑]

附录B 并发类库对比[编辑]

附录C 消息传递框架与完整的ATM示例[编辑]

附录D C++线程类库参考

简单理解compare_exchange_weak函数 compare_exchange_weak比compare_exchange_strong 阅读详情

相关推荐

compare_exchange_weak功能

函数会将原子变量的当前值与一个期望值进行比较,如果两者相等,则将原子变量的值更新为指定的新值;如果相等,则将期望值更新为原子变量的当前值。该函数可能会出现伪失败的情况,即即使原子变量的当前值与期望值相等,操作也可能返回false,但这并影响其在循环中重试以达到最终的更新目的。

doubleintfloat的博客 1352

同步-C++11之Atomic和CAS

1、概要 本文是无同步系列文章的第一篇,主要探讨C++11中的Atomic。 我们知道在C++11中引入了mutex和方便优雅的lock_guard。但是有时候我们想要的是性能更高的无实现,下面我们来讨论C++11中新增的原子操作类Atomic,我们可以利用它巧妙地实现无同步。 2、传统的线程同步 1 #include <thread> ...

weixin_30316097的博客 1077

C++并发编程实战:从理论到项目,整本书测试巩固指南

并发编程是现代软件开发的核心技术之一,它通过允许多个任务同时执行来提升程序性能。其原理主要围绕线程管理、共享数据同步和内存模型展开,旨在解决数据竞争和死等核心挑战。掌握并发编程的技术价值在于能够构建高性能、高响应性的服务器、游戏引擎和数据处理系统。在实际应用场景中,开发者常需实现线程池、无队列等并发组件。本文以《C++并发编程实战》为蓝本,通过设计分层测试框架和综合项目实战,系统性地串联**线程管理**、**共享数据保护**等关键知识点,帮助开发者将理论知识转化为解决实际工程问题的能力,并规避数据竞争

weixin_33951761的博客 486

C++C++原子操作:compare_exchange_weak详解

C++中的std::atomic::compare_exchange_weak是原子比较交换(CAS)操作的核心函数,主要用于无同步和无数据结构的实现。该函数提供单内存序和双内存序两个版本,默认使用顺序一致性内存序。其核心逻辑是原子化地比较并替换值,支持伪失败特性,必须在循环中使用。与强版本相比,弱版本性能更高但允许无理由失败。该函数适用于无计数器、无数据结构等场景,典型应用如官方示例中的无链表头插操作,通过循环CAS实现线程安全。使用时需注意内存序规则和伪失败处理,以平衡性能与正确性。

Ape's IT Blog 1266

[读书笔记][C++并发编程实战]一个线程安全的队列的实现

背景 我们都知道,线程之间是需要同步的,只有同步,才能保证共享的数据结构被有序的操作。 在一个经典的生产者消费者模型中,有生产者,消费者,今天就参考 CCIA(c++ concurrency in action, C++ 并发编程实战)来实现以下生产者消费者模型。 其中,核心是,我们必须写一个线程安全的队列。 我们用的是互斥变元 mutex 以及 条件变量,以及 lock_guard 和 unique_lock 。 以下就是代码: // // Created by zxzx on 2020/12/29. /

搜索引擎预备工程师 407

《Effective C++读书笔记(三)

一.实现 26.尽可能延后变量定义式出现的时间: a)      只有真的要用这个变量了,才进行定义。防止必要的定义造成浪费。     b)      如果可以通过copy构造函数构造就能省去对象默认构造并赋值的浪费。 c)      关于循环内使用一个对象,定义在循环外还是循环内的问题,这个本人纠结了好久。现在终于有相对明确的答案了: 定义在循环外需要:1个构造函数,1个析构函数,

puppet_master的专栏 696

《Effective c++读书笔记 5.实现

26.尽可能延后变量定义式的出现时间 两条准则 1.延后变量的定义,直到非得使用该变量的前一刻为止 原因:如果定义了用,会付出一次构造和析构的成本 2.甚至应该延后这份定义直到能够给它初值实参为止 “通过default构造函数构造出一个对象然后对它赋值” 比 “直接在构造时指定初值” 效率差 循环怎么定义变量? ●两种做法: 1.定义于循环外 Widget w; for(int i = 0; i < n; ++i){ w = ...; } 2.定义于循环内 for(int i = 0; i &l

ziggy7的博客 231

<<Effective C++>>读书笔记(3)

五.实现26.尽可能延后变量定义式出现的时间 a)只有真的要用这个变量了,才进行定义,防止必要的定义造成浪费 b)如果可以通过copy构造函数构造就能省去对象默认构造并赋值的浪费 c)关于循环内使用一个对象,定义在循环外还是循环内的问题. 定义在循环外需要:1个构造函数,1个析构函数,n个构造函数 定义在循环内需要:n个构造函数,n个析构函数 定义在循环外的话,会造成作用域污染.所以除

oyhy_的博客 423

Effective C++ 读书笔记(3.资源管理)

条款13:以对象管理资源 假设我们使用一个类来表示投资行为,各式各样的投资类型继承自一个root class Investment: class Investment{...}; 通过一个工厂函数供应我们的Investment对象: Inverstment* CreateInvestment(); 调用createInvestment的对象后,有责任删除之。用一个f函数: void f() { Inverstment * pInv=CreateInvestment(); ... delete p

weixin_42699130的博客 175

《Linux多线程muduo》读书笔记1——多线程下的析构函数

对象的安全析构 1. 问题 多线程下析构一个对象时,从何而知是否有别的线程正在执行该对象的成员函数? 我尝试的答案—— 引用计数。通过引用计数可以得知目前有多少个对象的成员函数被别人持有。 如何保证在执行成员函数期间,对象会在另一个线程被析构? 我尝试的答案—— 生存期的传递。使用shared_ptr保存对象。当某个线程执行这个shared_ptr对象的成员函数时,相当于生存期进行...

心灵迷宫 707

effective c++读书笔记()

资源管理

VanityLost_CY的博客 278

Effective STL读书笔记

1、慎重选择容器类型     a.标准STL序列容器:vector、string、deque、list     b.标准STL关联容器:set、 multiset、 map、 multimap     c.非标准序列容器:slist、 rope     d.非标准关联容器:hash_set、 hash_multiset、 hash_map、 hash_multimap     e.vec

大冰的小屋 875

详细解析了 compare_exchange_weak -----并发编程入门(三): 使用C++11实现无stack(lock-free stack)

时间2014-02-13 20:47:00 CSDN博客 相似文章 (0) 原文  http://blog.csdn.net/anzhsoft/article/details/19125619 添加到推刊 收藏到推刊 创建推刊 收 藏 取消 已收藏到推刊!

1万+

compare_exchange_weak详解

对于类型的变量atomic_var特点内容功能CAS(Compare And Swap):相等就替换类型weak允许虚假失败,适合 retry 循环关键参数expected是传引用,会在失败时被更新用途lock-free 数据结构(栈、队列、哈希表)和对比更高性能、更复杂、更容易出错常见错误忘了处理 expected 被修改、忽视内存序影响会自动更新expected// 读当前 head!// CAS 尝试替换 head为什么重新load()也可以继续工作?

Damon_X的博客 1270

C++11:原子交换函数compare_exchange_weak和compare_exchange_strong

C++11:原子交换函数compare_exchange_weak和compare_exchange_strong

a947568753的博客 816

compare_exchange_weak

实现无数据结构的基础是CAS:Compare & Set,或是 Compare & Swap。CAS用C语言描述的代码(来自Wikipedia Compare And Swap) int compare_and_swap (int* reg, int oldval, int newval) { ATOMIC(); int old_reg_val = *reg; if (old_reg_val == oldval) *reg = newval; END_A.

eckael的专栏 545

一篇看懂compare_exchange_weak和compare_exchange_strong的区别

通过这种方式,CAS 操作能够高效地协调多线程对共享资源的访问。

专注分享游戏引擎相关技术 1483

C++并发编程(七)无数据结构

C++并发编程实战》笔记

CSSS_2021的博客 2320
上一篇: C++高级编程(第3版) 读书笔记
下一篇: 《Mesos in Action》一些零碎的笔记(Mesos之于Kubernetes,犹如WebKit之于Chromium)
志_祥
博客等级 码龄24年 197粉丝 389原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值