github地址:https://github.com/rigtorp/MP...
- 对于
__cpp_lib_hardware_interference_size
这个功能测试宏示意了c++17新引入的feature : https://zh.cppreference.com/w...
相干:https://www.it1352.com/178422...
其含意是两个对象间防止假数据共享(false sharing,也被称为伪共享)的最小偏移量。
对于false sharing : https://www.cnblogs.com/cyfon...
#ifdef __cpp_lib_hardware_interference_sizestatic constexpr size_t hardwareInterferenceSize = std::hardware_destructive_interference_size;#elsestatic constexpr size_t hardwareInterferenceSize = 64;#endif
下面这段代码即获取了以后硬件条件下的防止伪共享的最小偏移量,如果编译器还没有实现这个feature,则自定义为64字节。(支流的硬件架构cache line 大小为64字节 : https://blog.csdn.net/midion9...)
为了防止伪共享的产生,让不同对象处于不同的缓存行即可,也就是设置偏移量为缓存行大小。
- 对于
__cpp_aligned_new
c++17引入的新feature,具体信息见: https://www.jianshu.com/p/7ce...
其作用是提供内存对齐版本的new运算符。
#if defined(__cpp_aligned_new)template <typename T> using AlignedAllocator = std::allocator<T>;#elsetemplate <typename T> struct AlignedAllocator { using value_type = T; T *allocate(std::size_t n) { if (n > std::numeric_limits<std::size_t>::max() / sizeof(T)) { throw std::bad_array_new_length(); }#ifdef _WIN32 auto *p = static_cast<T*>(_aligned_malloc(sizeof(T) * n, alignof(T))); if (p == nullptr) { throw std::bad_alloc(); }#else T *p; if (posix_memalign(reinterpret_cast<void **>(&p), alignof(T), sizeof(T) * n) != 0) { throw std::bad_alloc(); }#endif return p; } void deallocate(T *p, std::size_t) {#ifdef WIN32 _aligned_free(p);#else free(p);#endif }};#endif
如果编译器实现了aligned new的feature,则间接实现规范库版本的内存分配器,否则
自定义一个,依据平台不同应用_aligned_malloc/posix_memalign实现。
- 对于Slot类
template <typename T> struct Slot {~Slot() noexcept { if (turn & 1) { destroy(); }}template <typename... Args> void construct(Args &&... args) noexcept {static_assert(std::is_nothrow_constructible<T, Args &&...>::value, "T must be nothrow constructible with Args&&..."); new (&storage) T(std::forward<Args>(args)...);}void destroy() noexcept {static_assert(std::is_nothrow_destructible<T>::value, "T must be nothrow destructible"); reinterpret_cast<T*>(&storage)->~T();}T &&move() noexcept { return reinterpret_cast<T &&>(storage); }// Align to avoid false sharing between adjacent slotsalignas(hardwareInterferenceSize) std::atomic<size_t> turn = {0};typename std::aligned_storage<sizeof(T), alignof(T)>::type storage;};
下面是Slot类的实现,重点察看以下几个中央:
- 数据成员turn的修饰符含意
- 数据成员storage的作用
- 析构函数
- construct函数中的placement new操作
应用std::aligned_storage定义了一个大小最多为sizeof(T), 对其要求为alignof(T)的对象storage。并在construct函数中通过placement new操作在其上结构T类型对象。
这一系列操作的目标就是提供给用户自定义的依照任何对齐要求的内存申请与结构的形象能力,对于这套组合拳c++规范中有清晰的标注:
As with any other uninitialized storage, the objects are created using placement new and destroyed with explicit destructor calls.
参考文章:https://blog.csdn.net/ywcpig/... 和
https://en.cppreference.com/w...
应用alignas修饰符将数据成员turn的对齐要求批改为hardwardInterferenceSize,即文章第一局部定义的常量,因为构造体的大小必须是其数据成员最大对齐数的整数倍,因而不同Slot对象的storage不可能存在于同一个cache line中,防止了false sharing。
析构函数中依据turn是否为0选择性调用destroy函数析构对象,能够看到turn的另一个作用是标记此Slot中是否还存在T类对象。
tips:
对c++语法不够纯熟的同学能够再看下这段代码,波及到大括号初始化,类内初始化,xvalue的产生,可变参数的完满转发,noexcept等新规范个性。