c++ - 无锁、无等待、单生产者单消费者环形缓冲区是否可能在溢出时覆盖最近的数据?
问题描述
一段时间以来,我一直在研究无锁、无等待、C++ SPSC 环形缓冲区实现。对于缓冲区已满时的特别排队操作,我遇到了几种不同的方法来处理这种情况。比如这家伙对push和pop操作的实现如下:
bool push(const Element& item)
{
const auto current_tail = _tail.load(std::memory_order_relaxed); // 1
const auto next_tail = increment(current_tail);
if(next_tail != _head.load(std::memory_order_acquire)) // 2
{
_array[current_tail] = item; // 3
_tail.store(next_tail, std::memory_order_release); // 4
return true;
}
return false; // full queue
}
bool pop(Element& item)
{
const auto current_head = _head.load(std::memory_order_relaxed); // 1
if(current_head == _tail.load(std::memory_order_acquire)) // 2
return false; // empty queue
item = _array[current_head]; // 3
_head.store(increment(current_head), std::memory_order_release); // 4
return true;
}
他的方法只是在缓冲区已满时拒绝将新元素排队,这很好。之后,我一直在寻找一种方法来将此实现转换为在缓冲区耗尽时覆盖最近的数据。要做到这一点,根据这个家伙,当队列已满时,_head 索引也必须通过 push 操作推进。但是现在,两个线程能够写入必须同步的同一个变量。由于我不是 C++ 专家,我不能简单地弄清楚这是否可以通过添加一些原子加载或存储操作来简单地完成,但我的直觉告诉我这样的事情是不可能的,因为即使 _head 和 _tail 同步是调整得很好,那么 pop() 可能会得到一个被推送部分设置(或填充)的元素,即。两个函数中标记为“3”的行将不是原子的,并且可能出现肮脏的竞争条件。此外,我在 GitHub 和 Google 搜索中找不到这样的实现。
那么,这样的 SPSC 环形缓冲区是否可以实现保留无锁和无等待的特性呢?如果可能的话,我恳请您提供简明的说明或代码。另外,您能否就我在推送和弹出功能上进行转换的方法发表您的意见?
解决方案
推荐阅读
- maven - 为了创建可扩展的项目,声明 MAVEN 依赖项的正确/最佳方式是什么?
- php - 无法使用 curl_multi 访问字母主机
- grpc - Java中的gRPC - 如何接收文件内容作为响应
- android - 按部分文本在 ORMLite 中搜索
- php - PHP没有捕获ajax请求
- python - 如何将列表转换为 ASCII
- java - 在带有参数的注释之前未调用方面
- javascript - 用 JavaScript 中的键替换 JSON 对象数组中的所有值
- azure - 尝试在 Azure CLI 中获取 Azure IoT 中心的连接字符串时出错
- kubernetes - 从 Kubernetes 集群中安全关闭节点