C++并发编程实战
目录
[隐藏]基本线程管理[编辑]
- p18 RAII:~thread_guard:if(t.joinable())t.join();
- p29 std::this_thread::get_id()
在线程间共享数据[编辑]
- mutex
- p36 std::lock_guard<std::mutex> l(m); //RAII风格
- p45 std::lock可以用时锁住2个或更多的mutex?
- p46 让每个线程仅持有一个锁,--> 但是仍然有可能相互等待...
- p50 层次锁?
- p52 std::unique_lock??
- p57 臭名昭著的2次检查锁定模式:data race(~ C++内存模型)
- std::call_once(std::once_flag f, std::shared_ptr<T> res);
- p60 读写mutex:boost::shared_mutex
- p61 递归锁(略)
同步[编辑]
- std::condition_variable data_cond;
- data_cond.wait( lk, []{return !queue.empty()} );
- data_cond.notify_one(); //唤醒一个,注意,上面2句都需要在std::unique_lock的保护范围内(queue是共享变量)
- p68 threadsafe_queue?
- 使用future等待一次性事件
- std::future<T> result = std::async(doWork); //将在result.get()时阻塞
- std::packaged_task<T=Callable> -> get_future() //高层抽象
- std::promise*
- set_value / get_future
- std::shared_future*
- std::chrono::
- system_clock, steady_clock, high_resolution_clock
- duration
- time_point
- std::timed_mutex:try_lock_for / try_lock_until
- p91 基于future的parallel_quick_sort
- p92 spawn_task
- typedef std::result_of<F(A&&)>::type result_type; //?
C++内存模型和原子操作[编辑]
- std::atomic_flag f = ATOMIC_FLAG_INIT;
- lock: while(f.test_and_set(std::memory_order_acquire)); //可以运行时切换std::memory_order_*参数到底是个什么鬼??
- unlock: fl.clear(std::memory_order_release);
- 更通用的std::atomic<bool>
- b.compare_exchange_weak(expected_value, memory_order_acq_rel, memory_order_acquire); //?
- std::atomic<T*>上的操作
- p108 p.fetch_add(3, std::memory_order_release);
- std::atomic<UDT>
- UDT必须有平凡的拷贝赋值(且必须是编译器默认生成的,POD?)、必须是按位相等可比较的
- 原子操作函数*
- p114 happens-before和synchronizes_with
- p116 6种内存顺序:
- 代表了3种模型:
- 顺序一致(最容易理解的,但在多处理器但弱顺序机器上有性能问题)
- 非顺序一致:*
- ?唯一的要求是所有的线程对每个独立变量的修改顺序达成一致(“达成一致”指的是什么意思???)
- 松弛:原子类型上但操作不参与synchronizes_with关系,单线程中的同一个变量的操作仍然服从happens-before关系
- p124 获得-释放:靠,仍然有点费解
- 获取-释放顺序传递性同步*
- p130 memory_order_consume:数据依赖(?)
- 代表了3种模型:
- p133 释放序列和synchronizes_with **
- 内存屏障
- p137 用原子操作排序非原子操作*
基于锁的并发数据结构[编辑]
- p162 设计一个细粒度的map数据结构
- RB-tree(std::map)从访问根节点开始,... 尽管线程沿着树往下移动的时候会释放这个锁 ...
- 已排序数组
- hashmap:可以在每个桶上有一个独立的锁
- p165 编写一个使用锁的线程安全链表
- 基本思想是每个节点使用一个mutex(细粒度锁)... ?如果要修改相邻的2个节点,需要同时上锁吧?
- 可以参考Linux Kernel里的list实现...
设计无锁并发数据结构[编辑]
- p174 无锁的线程安全栈*
- 不是无等待的!(线程死循环忙等不就相当于被“锁住”了吗?)
- p178 管理内存(防止泄露):你想释放一个节点,但必须确保没有别的线程引用时才能这么做,... 这从根本上意味着需要为节点写一个专用GC
- p182 用风险指针(hazard pointers)检测不能回收的节点 *
- p189 使用引用计数检测节点 *
- p194 将内存模型应用至无锁栈 *
- p198 无锁队列
- 编写无锁数据结构的准则
- p210 使用std::memory_order_seq_cst
- 使用无锁内存回收模式
- 当心ABA问题
- 识别忙于等待的循环及辅助其他线程
设计并发代码[编辑]
- p219 以任务类型划分工作
- p221 划分线程间的任务队列(管道)
- 影响性能的因素
- p223 数据竞争和缓存乒乓
- 假共享(CPU的片内cache line)
- 额外考虑
- p230 并行算法中的异常安全 *
- 在实践中设计并发代码:STL算法的并行实现 **
- std::for_each
- std::find
- std::partial_sum
高级线程管理[编辑]
- 线程池
- 中断线程(这里的思想似乎来自于Java interrupt()?)
多线程应用的测试与调试[编辑]
- 不必要的阻塞:死锁、活锁、IO阻塞
- 竞争条件
- 多线程测试
- ps:Google Android上的Address Sanitizer (ASAN)工具?