【问题标题】:Ring buffer for a wait-free producer and a blocking consumer无等待生产者和阻塞消费者的环形缓冲区
【发布时间】:2019-01-17 01:17:43
【问题描述】:

我有一个生产者线程,它产生对象的速度可能(暂时)太快而消费者线程无法消费。因此,我想要一个 FIFO 来缓冲剩余的工作。一旦 FIFO 已满,生产者将简单地退出或稍后重试。此外,我希望能够通知消费者不再需要做任何工作(无需将特殊对象排入 FIFO)。生产者不能慢下来,消费者不能浪费CPU周期,所以我有以下要求:

  • 固定大小的环形缓冲区。
  • 生产者永远不会等待:它需要能够尽快将元素加入队列。
  • 消费者应该能够阻止: 不忙等待潜在的慢生产者。混合锁会很好。

我正在设想以下 C++ 类:

template <typename T, std::size_t N>
class spsc_circular_half_blocking {
    std::array<T, N> buffer;
    // bookkeeping, atomics, mutexes etc. go here
public:
    bool try_push(const T&); // returns whether object could be enqueued
    void notify(); // notifies consumer
    bool wait_pop(T&); // returns whether object was dequeued or notification was received
};

能够就地修改元素会很好。它还可以使用缓冲区的动态分配(例如,将大小传递给构造函数,缓冲区是unique_ptr)。

现在回答我的问题。这件事是否可能(至少在 x86 上)?

  • 如果是,它将如何工作?我真的很想要一些实现,最好但不一定是 C++。
  • 如果没有,为什么不呢?

相关材料的指针,即使它不能完全满足我的需求,也将不胜感激。

【问题讨论】:

  • 可以使用信令机制通知消费者。
  • github.com/cameron314/readerwriterqueue。它有一个阻塞版本。
  • 我还没有看到任何关于无锁循环缓冲区的论文,所以很可能还没有发明。无锁队列已经存在了二十多年。无论如何,要求建议异地资源在这里是题外话。
  • 您是否使用互斥锁和条件变量对阻塞版本进行基准测试,发现速度不够快?
  • @Maxim 我有一个性能很差的解决方案,涉及两个无等待队列,这是一种非常人为的方式,我正在努力改进。我真的需要某种形式的try_push,因为在我的情况下,一旦达到队列限制就继续操作是不明智的。生产者永远不必等待消费者是一项严格的要求。

标签: c++ multithreading producer-consumer lock-free wait-free


【解决方案1】:

谷歌发现了这个,不知道但也许值得研究一下:

免等待多生产者多消费者环形缓冲区:

https://www.osti.gov/servlets/purl/1531271

【讨论】:

  • 通常不鼓励仅链接的答案,尽管整个问题要求如此之多,以至于它基本上是一个资源请求。不过,通常只发布一个链接应该用评论来完成,而不是答案。 尤其是,如果您只是在 Google 上随机发现它并且自己对此无话可说。
【解决方案2】:

一种解决方案是使用 boost single-producer single-consumer queue 与您自己的信号和阻塞。

【讨论】:

  • 这似乎是一个非常有用的方法!但我不明白为什么我必须在生产者网站上查看read_available() == 0。在这两种情况下通知消费者还不够吗?另外,从生产者站点调用read_available() 不会受到竞争条件的影响吗?该手册似乎确实建议不要在生产者中使用read_available()
  • @purefanatic 我修改了答案并为您添加了一个可行的解决方案。
  • @PeterCordes 我非常喜欢你对compare_exchange_strong(UNBLOCK, READY) 的想法。我认为在获取UNBLOCK 时丢失队列条目的情况可能不会经常发生,但是,它巧妙地处理了这种情况。 READY 的存储不需要在锁定状态下完成,因为生产者不关心或等待这个特定状态。更新了解决方案。
  • @PeterCordes 等待条件变量释放互斥体。
  • 你为什么要在这里删除你所有的代码?我以前发现它很有用。
猜你喜欢
  • 2017-04-07
  • 2019-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-13
  • 2011-03-21
  • 1970-01-01
相关资源
最近更新 更多