没有优先级倒置的环形缓冲区

use*_*715 8 c++ concurrency circular-buffer

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

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;
};
Run Code Online (Sandbox Code Playgroud)

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

我可以在访问周围放置一个互斥体来开始和结束但如果高优先级线程必须等待低优先级线程获取的锁定,那么这将导致优先级倒置.

我可能能够使用原子操作来解决问题,但我不知道有一个很好的跨平台库提供这些.

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

Mar*_*som 4

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

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

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

  • count即使您获得了该值,您也要考虑到该值可能已经过时的事实。在读取线程中,count将返回您可以信赖的最小计数;因为写入线程count将返回最大计数,而真实计数可能会更低。