empty std::queue 将数据推送到陈旧项目的末尾

empty std::queue pushing data to end of stale items

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

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

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

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

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

我担心线程安全,所以我添加了一个额外的缓冲队列,并且只在 "unlocked" 时推送到收件箱。而且一旦我 运行 无论如何我都没有看到任何冲突发生!

推送代码:

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;

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

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

另一方面,如果您有多个 CPU 核心需要处理,则有必要在显式栅栏、关键位置塞满,或者使用 C++11 类 点赞 std::mutex,它将为您解决这个问题。

但是使用单个 CPU 的原始用例,并且没有内存防护问题,如果您可以保证:

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

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

那么 std::queue 的一个潜在替代方案值得在这里探索,即滚动您自己的简单队列,只使用静态 std::array,或者 std::vectorint 头指针和一个 int 尾指针。 google 搜索应该可以找到大量实施此简单算法的示例:

拉取器检查"if head != tail",如果是,则读取queue[head]中的消息并递增head。增量表示:head=(head+1)%queuesize。拉取器检查递增 tail(也模队列大小)是否导致 head,如果是,则队列已满(根据此方法的先决条件,这是不应该发生的事情)。如果不是,则将消息放入队列[tail],并增加 tail.

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

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

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