8

我有一个需要将数据传递给低优先级进程的高优先级进程。我编写了一个基本的环形缓冲区来处理数据的传递:

class RingBuffer {
  public:
    RingBuffer(int size);
    ~RingBuffer();

    int count() {return (size + end - start) % size;}

    void write(char *data, int bytes) {
      // some work that uses only buffer and end
      end = (end + bytes) % size;
    }

    void read(char *data, int bytes) {
      // some work that uses only buffer and start
      start = (start + bytes) % size;
    }

  private:
    char *buffer;
    const int size;
    int start, end;
};

这就是问题所在。假设低优先级进程有一个预言机,它准确地告诉它需要读取多少数据,因此count()永远不需要调用。然后(除非我遗漏了什么)没有并发问题。但是,只要低优先级线程需要调用count()(高优先级线程可能也想调用它以检查缓冲区是否太满),count() 中的数学运算或更新可能会结束不是原子的,引入了一个错误。

我可以在开始和结束的访问周围放置一个互斥锁,但是如果高优先级线程必须等待低优先级线程获取的锁,这将导致优先级反转。

我也许可以使用原子操作解决一些问题,但我不知道有一个很好的跨平台库提供这些。

是否有避免这些问题的标准环形缓冲区设计?

4

3 回答 3

4

只要您遵守以下准则,您所拥有的就应该没问题:

  • 只有一个线程可以进行写入。
  • 只有一个线程可以读取。
  • 更新和访问startend是原子的。这可能是自动的,例如 Microsoft 声明:

对正确对齐的 32 位变量的简单读写是原子操作。换句话说,您最终不会只更新变量的一部分;所有位都以原子方式更新。

  • count即使您获得价值,您也可以考虑可能已过时的事实。在阅读线程中,count将返回您可以依赖的最小计数;因为写入线程count将返回最大计数,而真正的计数可能会更低。
于 2011-04-21T16:11:47.543 回答
2

Boost 提供了一个循环缓冲区,但它不是线程安全的。不幸的是,我不知道有任何实现。

即将推出的 C++ 标准将原子操作添加到标准库中,因此它们将在未来可用,但大多数实现尚不支持它们。

我没有看到任何跨平台解决方案可以count在两个线程都写入时保持理智,除非您实现锁定。

通常,您可能会使用消息系统并强制低优先级线程请求高优先级线程进行更新,或类似的东西。例如,如果低优先级线程消耗 15 个字节,它应该要求高优先级线程将计数减少 15。

本质上,您将限制对高优先级线程的“写入”访问,并且只允许低优先级线程读取。这样就可以避免所有的锁定,高优先级的线程就不用担心等待低级线程完成写入,使高优先级线程真正的高优先级。

于 2011-04-21T16:16:45.687 回答
1

boost::interprocess提供跨平台的原子功能boost/interprocess/detail/atomic.hpp

于 2011-04-21T16:25:43.130 回答