我正在研究单生产者单消费者环形缓冲区实现,我有两个要求:
- 将单个分配的环形缓冲区实例与缓存行对齐。
- 将环形缓冲区中的字段与高速缓存行对齐(以防止错误共享)。
我的课看起来像这样:
#define CACHE_LINE_SIZE 64 // To be used later.
template<typename T, uint64_t num_events>
class RingBuffer { // This needs to be aligned to a cache line.
public:
....
private:
std::atomic<int64_t> publisher_sequence_ ;
int64_t cached_consumer_sequence_;
T* events_;
std::atomic<int64_t> consumer_sequence_; // This needs to be aligned to a cache line.
};
让我首先解决点1,即对齐类的单个堆分配实例。有几种方法:
使用c ++ 11
alignas(..)
说明符:template<typename T, uint64_t num_events> class alignas(CACHE_LINE_SIZE) RingBuffer { public: .... private: // All the private fields. };
使用
posix_memalign(..)
+放置new(..)
而不更改类定义。这受制于与平台无关的问题:void* buffer; if (posix_memalign(&buffer, 64, sizeof(processor::RingBuffer<int, kRingBufferSize>)) != 0) { perror("posix_memalign did not work!"); abort(); } // Use placement new on a cache aligned buffer. auto ring_buffer = new(buffer) processor::RingBuffer<int, kRingBufferSize>();
使用GCC / Clang扩展
__attribute__ ((aligned(#)))
template<typename T, uint64_t num_events> class RingBuffer { public: .... private: // All the private fields. } __attribute__ ((aligned(CACHE_LINE_SIZE)));
我尝试使用C ++ 11标准化
aligned_alloc(..)
函数代替,posix_memalign(..)
但是在Ubuntu 12.04上的GCC 4.8.1在以下位置找不到定义stdlib.h
是否所有这些都可以做同一件事?我的目标是高速缓存行对齐,因此任何对对齐有限制(例如双字)的方法都不会这样做。alignas(..)
次要目标是使用标准的平台独立性。
我不清楚是否alignas(..)
和__attribute__((aligned(#)))
有一定的限额,这可能是本机上的高速缓存线以下。我再也无法重现此信息,但是在打印地址时,我想我并不总是使用来获得64字节对齐的地址alignas(..)
。相反,posix_memalign(..)
似乎总是可行。我再也不能重现这个,所以也许我是在犯错误。
第二个目标是将类/结构中的字段与高速缓存行对齐。我这样做是为了防止虚假共享。我尝试了以下方法:
使用C ++ 11
alignas(..)
说明符:template<typename T, uint64_t num_events> class RingBuffer { // This needs to be aligned to a cache line. public: ... private: std::atomic<int64_t> publisher_sequence_ ; int64_t cached_consumer_sequence_; T* events_; std::atomic<int64_t> consumer_sequence_ alignas(CACHE_LINE_SIZE); };
使用GCC / Clang扩展
__attribute__ ((aligned(#)))
template<typename T, uint64_t num_events> class RingBuffer { // This needs to be aligned to a cache line. public: ... private: std::atomic<int64_t> publisher_sequence_ ; int64_t cached_consumer_sequence_; T* events_; std::atomic<int64_t> consumer_sequence_ __attribute__ ((aligned (CACHE_LINE_SIZE))); };
这两种方法似乎都对齐consumer_sequence
到对象开始之后64字节的地址,因此consumer_sequence
缓存是否对齐取决于对象本身是否缓存对齐。我的问题是-是否有更好的方法可以做到这一点?
编辑:
原因aligned_alloc
在我的计算机上不起作用是因为我使用的是eglibc 2.15(Ubuntu 12.04)。它适用于更高版本的eglibc。
在手册页中:该功能aligned_alloc()
已添加到版本2.16的glibc中。
这对我来说毫无用处,因为我不能使用eglibc / glibc这样的最新版本。