我是一个帮助翻译的助手。以下是需要翻译的内容:
我有一个类,用于存储某些实时数据的最新值(大约每秒150亿个事件)。
假设它看起来像这样:
class DataState
{
Event latest_event;
public:
//pushes event atomically
void push_event(const Event __restrict__* e);
//pulls event atomically
Event pull_event();
};
我需要能够原子地推送事件并以严格的顺序保证进行拉取操作。现在,我知道我可以使用自旋锁,但考虑到巨大的事件速率(超过每秒100万次)和高度并发性,我更愿意使用无锁操作。
问题在于,Event的大小为64字节。 当前X86 CPU上没有任何CMPXCHG64B指令(截至'16年8月)。 因此,如果我使用std :: atomic ,我必须链接到libatomic,后者在内部使用互斥锁(太慢了)。
所以我的解决方案是代替原子交换值的指针。 问题是,动态内存分配会成为这些事件速率的瓶颈。 因此……我定义了一个我称之为“环形分配器”的东西:
/// @brief Lockfree Static short-lived allocator used for a ringbuffer
/// Elements are guaranteed to persist only for "size" calls to get_next()
template<typename T> class RingAllocator {
T *arena;
std::atomic_size_t arena_idx;
const std::size_t arena_size;
public:
/// @brief Creates a new RingAllocator
/// @param size The number of elements in the underlying arena. Make this large enough to avoid overwriting fresh data
RingAllocator<T>(std::size_t size) : arena_size(size)
{
//allocate pool
arena = new T[size];
//zero out pool
std::memset(arena, 0, sizeof(T) * size);
arena_idx = 0;
}
~RingAllocator()
{
delete[] arena;
}
/// @brief Return next element's pointer. Thread-safe
/// @return pointer to next available element
T *get_next()
{
return &arena[arena_idx.exchange(arena_idx++ % arena_size)];
}
};
那么我的DataState类可能看起来像这样:
class DataState
{
std::atomic<Event*> latest_event;
RingAllocator<Event> event_allocator;
public:
//pushes event atomically
void push_event(const Event __restrict__* e)
{
//store event
Event *new_ptr = event_allocator.get_next()
*new_ptr = *e;
//swap event pointers
latest_event.store(new_ptr, std::memory_order_release);
}
//pulls event atomically
Event pull_event()
{
return *(latest_event.load(std::memory_order_acquire));
}
};
只要我将我的环形分配器大小设置为可能同时调用函数的最大线程数,就不会有覆盖pull_event可能返回的数据的风险。此外,所有内容都非常本地化,因此间接引用不会导致较差的缓存性能。这种方法可能存在什么潜在问题吗?