【问题标题】:ring buffer without priority inversion没有优先级反转的环形缓冲区
【发布时间】:2011-04-21 15:51:35
【问题描述】:

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

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() 中的数学运算或更新到 end 不是原子的,引入了一个错误。

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

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

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

【问题讨论】:

  • 您对使用的平台有什么限制吗?
  • @Peter 让我们假设 x86(IIRC 32 位写入对齐地址是原子的)虽然越便携越好。
  • 这里是一个队列,它的运行主要是免等待software.intel.com/en-us/articles/…

标签: c++ concurrency circular-buffer


【解决方案1】:

只要您遵守这些准则,您所拥有的应该是可以的:

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

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

  • 您允许count 可能已过期,即使您获得了价值。在阅读线程中,count 将返回您可以依赖的最小 计数;对于写作线程count 将返回 最大 计数,而真正的计数可能会更低。

【讨论】:

  • 编译器是否存在将更新拆分为非原子步骤序列的风险?即把write()的最后一行变成end += bytes; end %= size;?
  • 编译器可以非原子方式计算 RHS,根据您的平台,甚至可以非原子方式存储一个 int(即在 8 位平台上使用两个 8 位写入存储一个 16 位 int )。
  • @user168715,如果您绝对不相信您的编译器会做正确的事情,请创建一个 volatile 临时变量来保存计算,然后将其复制以进行更新。
【解决方案2】:

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

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

我没有看到任何跨平台解决方案来保持count 在两个线程都写入它时保持正常,除非您实施锁定。

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

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

【讨论】:

    【解决方案3】:

    boost::interprocessboost/interprocess/detail/atomic.hpp 中提供跨平台的原子函数

    【讨论】:

      猜你喜欢
      • 2010-11-28
      • 2014-01-23
      • 2012-04-04
      • 1970-01-01
      • 2015-05-31
      • 2018-10-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多