0

我正在使用 std::queue 来缓冲网络上的消息(在这种情况下为 CAN 总线)。在中断期间,我将消息添加到“收件箱”。然后我的主程序检查队列是否为空,如果不是则处理消息。问题是,队列被弹出直到空(它从 退出while (! inbox.empty()),但是下次我将数据推送到它时,它可以正常工作,但旧数据仍然挂在后面。

例如,第一条消息将“1”推送到队列中。循环读取

  • 1

下一条消息是“2”。下一个阅读是

  • 2
  • 1

如果我在另一次阅读之前收到两条消息,“3”,“4”,那么下一次阅读将是

  • 3
  • 4
  • 2
  • 1

我很迷茫。我也在使用 STM32F0 ARM 芯片和在线 mbed,不知道这是否在硬件上运行不佳或什么!

我担心线程安全,所以我添加了一个额外的缓冲区队列,并且只在它“解锁”时推送到收件箱。一旦我运行它,我就没有看到任何冲突发生!

推送代码:

if (bInboxUnlocked) {
    while (! inboxBuffer.empty()) {
        inbox.push (inboxBuffer.front());
        inboxBuffer.pop();
    }
    inbox.push(msg);
} else {
    inboxBuffer.push(msg);
    printf("LOCKED!");
}

主程序读取代码

bInboxUnlocked = 0;
while (! inbox.empty()) {
    printf("%d\r\n", inbox.front().data);
    inbox.pop();
}
bInboxUnlocked = 1;

有人想吗?我用错了吗?还有其他方法可以轻松完成我正在做的事情吗?我希望缓冲区足够小,可以实现一个小的循环数组,但是手头有队列,我希望不必这样做。

4

1 回答 1

1

根据我从基本的 Google 搜索中得出的信息,您的 CPU 本质上是一个单核 CPU。如果是这样,那么这里不应该有任何内存防护问题需要处理。

另一方面,如果您在这里要处理多个 CPU 内核,则有必要在显式围栏、关键位置或使用 C++11 类(如 std::mutex)来处理这是给你的。

但是,如果您可以保证:

A)在队列耗尽之前,您希望通过队列中的中断处理代码缓冲的消息数量有一定的上限,并且:

B)您正在缓冲的消息是POD

然后,在这里值得探索的一个潜在替代方案std::queue是滚动您自己的简单队列,只使用一个 static std::array,或者可能是一个std::vector,一个int头指针和一个int尾指针。谷歌搜索应该找到很多实现这个简单算法的例子:

puller 检查“if head != tail”,如果是,则读取消息queue[head]并增加 head。增量意味着:head=(head+1)%queuesize。拉取程序检查是否递增tail(也以队列大小为模)导致head,如果是,则队列已填满(根据此方法的先决条件,这是不应该发生的事情)。如果不是,则将消息放入 queue[tail],并增加 tail。

如果所有这些操作都以正确的顺序完成,净效果将与使用相同,std::queue但:

1)没有它使用的开销std::queue和堆分配。应该是嵌入式平台的重大胜利。

2) 由于队列是一个向量,在连续内存中,这应该利用传统 CPU 中经常出现的 CPU 缓存。

于 2016-01-13T03:48:33.943 回答