内存模型
多线程的基础是定义良好的内存模型。对内存有基本的了解,有助于更深入地了解多线程的挑战。
不要使用volatile进行同步
C++与C#或Java相比,volatile
关键字没有多线程语义。在C#或Java中,volatile
声明了一个原子变量,如std::atomic
在C++中声明了一个原子一样,通常用于可以进行更改的对象。由于这一特性,没有优化的存储会发生在缓存中。
不要让程序无锁
这个建议听起来很荒谬,但是这个建议的理由很简单,无锁编程非常容易出错,并且需要在这个领域是专家级别的人,才能保证很少出错。如果需要实现无锁的数据结构,请务必注意ABA问题。
如果使用无锁程序,请使用成熟的模式
如果已经确定要使用无锁方案,那么请使用成熟的模式。
简单的共享原子布尔值或原子计数器。
使用线程安全,甚至无锁的容器来支持消费者/生产者的场景。如果使用的容器是线程安全的,则可以将值放入容器中或从容器中取出,而不必担心同步的问题。这就将应用程序的挑战转移到基础设施中。
不要构建自定义的抽象方式,尽量使用当前语言能够保证的方式
共享变量的线程安全初始化,可以通过多种方式完成。可以依赖于C++运行时的保证,比如:常量表达式、带有块作用域的静态变量,或者使用函数std::call_once
与std::once_flag
组合使用。这里用C++编程,即使使用非常复杂的获取-发布语义,也可以构建基于原子的抽象。一开始最好不要这样做,除非不得已。这意味着,通过度量关键代码的性能来确定瓶颈时,只有当明确自定义版本比当前语言默认的方式性能更好时,再进行更改。
不要重新发明轮子
Boost.Lockfree
Boost.Lockfree支持三种不同的数据结构:
Queue:无锁的多生产/多消费者队列
Stack:无锁的多产品/多消费者堆栈
spsc_queue:无等待的单生产者/单消费者队列(通常称为环形缓冲区)
CDS
CDS代表并发数据结构,包含许多侵入式(非拥有)和非侵入式(拥有)容器。因为它们会自动管理元素,所以标准模板库的容器是非侵入的。
堆栈(无锁)
队列和带优先级的队列 (无锁)
有序列表
有序的set和map(无锁和有锁)
无序的set和map(无锁和有锁 )
Last updated
Was this helpful?