gpt4 book ai didi

c++ - 没有原子的 SPSC 无锁队列

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:20:25 43 4
gpt4 key购买 nike

我的记录器有一个 SPSC 队列。

当然不是通用的SPSC无锁队列。

但是,考虑到关于它的使用方式、目标架构等的一系列假设,以及一些可接受的权衡(我将在下面详细介绍),我的问题基本上是,它安全吗/它有效吗?

  • 它只会在 x86_64 架构上使用,因此写入 uint16_t 将是原子的。
  • 只有生产者更新tail
  • 只有消费者更新head
  • 如果生产者读取 head 的旧值,看起来队列中的空间比实际少,这在使用 is 的上下文中是可以接受的限制。<
  • 如果消费者读取 tail 的旧值,看起来队列中等待的数据比实际少,这也是一个可接受的限制。

上述限制是可以接受的,因为:

  • 消费者可能不会立即获得最新的tail,但最终会到达最新的tail,并记录排队的数据。
  • 生产者可能不会立即获得最新的head,因此队列看起来比实际情况更满。在我们的负载测试中,我们发现我们记录的数量与队列的大小,以及记录器清空队列的速度,这个限制没有影响 - 队列中总是有空间。

最后一点,volatile 的使用是必要的,以防止每个线程只读取的变量被优化掉。

我的问题:

  • 这个逻辑正确吗?
  • 队列线程安全吗?
  • volatile 是否足够?
  • volatile 是否必要?

我的队列:

class LogBuffer
{
public:
bool is_empty() const { return head_ == tail_; }
bool is_full() const { return uint16_t(tail_ + 1) == head_; }
LogLine& head() { return log_buffer_[head_]; }
LogLine& tail() { return log_buffer_[tail_]; }
void advance_head() { ++head_; }
void advance_hail() { ++tail_; }
private:
volatile uint16_t tail_ = 0; // write position
LogLine log_buffer_[0xffff + 1]; // relies on the uint16_t overflowing
volatile uint16_t head_ = 0; // read position
};

最佳答案

Is this logic correct?

是的。

Is the queue thread safe?

没有。

Is volatile sufficient? Is volatile necessary?

不,两者都是。 Volatile 不是使任何变量成为线程安全的神奇关键字。您仍然需要为索引使用原子变量或内存屏障,以确保在您生产或使用项目时内存顺序正确。

更具体地说,在为队列生成或使用项目后,您需要发出内存屏障以保证其他线程将看到更改。当您更新原子变量时,许多原子库会为您做这件事。

顺便说一句,使用“was_empty”而不是“is_empty”来明确它的作用。此调用的结果是一个时间实例,它可能在您对其值采取行动时发生了变化。

关于c++ - 没有原子的 SPSC 无锁队列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27139260/

43 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com