基于数组的有界缓冲区中的空元素

Empty element in array-based bounded buffer

本文关键字:缓冲区 元素 数组 于数组      更新时间:2023-10-16

我有一个典型的生产者/消费者问题。生产者的代码是这样的:

#define BUFFER_SIZE 10
while (true) {
  /* Produce an item */
  while (( (in + 1) % BUFFER_SIZE)  == out)
  ;   /* do nothing -- no free buffers */
  buffer[in] = item;
  in = (in + 1) % BUFFER_SIZE;
}

消费者是:

while (true) {
  while (in == out)
  ; // do nothing -- nothing to consume
  // remove an item from the buffer
  item = buffer[out];
  out = (out + 1) % BUFFER_SIZE;
  return item;
}

这很好,但问题是,当前八个元素以及in=9out=0被填充时,生产者坐在那里,不填充最后(第九)个元素。当例如in=4out=5时也会发生这种情况。在每种情况下,都会有一个元素为空,并且即使有一个插槽仍然为空,队列也会显示为"已满"。

我可以想出一些复杂的检查,但我需要知道是否有一个干净的解决方案来填充整个队列。我尝试过先递增,然后再放入item,但也遇到了类似的问题。(用-1inout初始化也不起作用)。

请参阅维基百科关于这个主题的内容。最简单的解决方案似乎是:

  • 始终保持一个插槽为空:如果in == out,则缓冲区为空;如果in == out - 1,则缓冲区已满
  • num_unread_items替换out;执行简单数学运算从num_unread_itemsin中检索out

但是存在与计数读取&写入操作(在单独的变量中或直接在inout中);或者跟踪除了当前inout之外的最后一次操作是读取还是写入,这允许您消除缓冲区已满/缓冲区已空的情况的歧义。

在大学的一堂操作系统开发课上,我有一位兼职老师声称,不可能有一个只使用软件的解决方案来使用缓冲区中的所有N个元素。我用我决定称之为赛道解决方案的东西证明了他错了(灵感来自于我喜欢跑赛道的事实)。

在赛道上,你不局限于400米的比赛;一场比赛可以包括一圈以上。如果两个跑步者并驾齐驱会发生什么在比赛中?你怎么知道他们是打成平手,还是一个跑者超过了另一个?答案很简单:在比赛中,我们不监控跑步者的位置在赛道上;我们监测每个跑步者走过的距离。因此,当两名选手并驾齐驱时,我们可以区分平局和一名选手搭接另一个。

因此,我们的算法有一个N元素数组,并管理2N个竞赛。在他们完成各自的2N比赛之前,我们不会将生产者/消费者的计数器重新设置为零。我们不允许生产商领先消费者一圈以上,也不允许消费者领先生产商。事实上,我们只需要监控生产者和消费者之间的距离。

代码如下:

Item track[LAP];
int consIdx = 0;
int prodIdx = 0;
void consumer()
{ while(true)
  { int diff = abs(prodIdx - consIdx);
    if(0 < diff) //If the consumer isn't tied
    { track[consIdx%LAP] = null;
      prodIdx = (prodIdx + 1) % (2*LAP);
    }
  }
}
void producer()
{ while(true)
  { int diff = (prodIdx - consIdx);
    if(diff < LAP) //If prod hasn't lapped cons
    { track[prodIdx%LAP] = Item();      //Advance on the 1-lap track.
      prodIdx = (prodIdx + 1) % (2*LAP);//Advance in the 2-lap race.
    }
  }
}

我最初解决这个问题已经有一段时间了,所以这是我最好的回忆。希望我没有忽略任何错误。希望这能有所帮助!