empty std :: queue将数据推送到过时的项目结束

时间:2016-01-13 03:23:21

标签: c++ multithreading queue std mbed

我正在使用std :: queue来缓冲网络上的消息(在这种情况下是CAN总线)。在中断期间,我将消息添加到&#34;收件箱&#34;。然后我的主程序检查每个循环,如果队列是空的,如果不处理消息。问题是,队列弹出直到空(它从while (! inbox.empty())退出,但是下次我将数据推送到它时,它正常工作但旧数据仍然在后面停留。< / p>

例如,第一条消息推送&#34; 1&#34;到队列。循环读取

  • 1

下一条消息是&#34; 2&#34;。下一步是

  • 2
  • 1

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

  • 3
  • 4
  • 2
  • 1

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

我担心线程安全,所以我添加了一个额外的缓冲队列,只有当它解锁时才会推送到收件箱。#34;。一旦我跑了这个,我还没有看到任何冲突发生!

Pusher代码:

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;

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

1 个答案:

答案 0 :(得分:1)

基于我从基本的谷歌搜索中可以得出的结论,你的CPU本质上是一个单核CPU。如果是这样,那么在这里不应该有任何内存屏障问题需要处理。

另一方面,如果你有多个CPU内核需要处理,那么有必要在关键位置填写显式围栏,或者使用像std :: mutex这样的C ++ 11类,为你照顾这个。

但是如果你能保证:

,那么使用单个CPU的原始用例,并且没有内存防护问题。

A)在排队之前,队列中的中断处理代码预计会缓冲的消息数有一定的上限,并且:

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

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

拉拔器检查“if head!= tail”,如果是,则读取int中的消息并递增头部。增量意味着:head =(head + 1)%queuesize。拉出器检查递增queue[head](也是模数队列化)是否导致tail,如果是,则队列已填满(根据此方法的先决条件,不应发生这种情况)。如果没有,将消息放入队列[tail],并增加尾部。

如果所有这些操作都按照正确的顺序完成,那么净效应与使用head相同,但是:

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

2)由于队列是一个向量,在连续的内存中,这应该利用CPU缓存(通常就是这种情况,使用传统的CPU)。