empty std::queue 将数据推送到陈旧项目的末尾
empty std::queue pushing data to end of stale items
我正在使用 std::queue 来缓冲我的网络(在本例中为 CAN 总线)上的消息。在中断期间,我将消息添加到 "inbox"。然后我的主程序检查每个周期是否队列为空,如果没有则处理消息。问题是,队列被弹出直到为空(它从 while (! inbox.empty())
退出,但下次我将数据推送到它时,它可以正常工作,但旧数据仍然挂在后面。
例如,第一条消息将“1”推送到队列。循环读取
- 1
下一条消息是“2”。下一个阅读是
- 2
- 1
如果我在另一条消息“3”、“4”之前收到两条消息,那么下一条消息将是
- 3
- 4
- 2
- 1
我很困惑。我也在使用 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::vector
,int
头指针和一个 int
尾指针。 google 搜索应该可以找到大量实施此简单算法的示例:
拉取器检查"if head != tail",如果是,则读取queue[head]
中的消息并递增head。增量表示:head=(head+1)%queuesize。拉取器检查递增 tail
(也模队列大小)是否导致 head
,如果是,则队列已满(根据此方法的先决条件,这是不应该发生的事情)。如果不是,则将消息放入队列[tail],并增加 tail.
如果所有这些操作都以正确的顺序完成,净效果将与使用 std::queue
相同,但是:
1) 没有 std::queue
的开销和它使用的堆分配。应该是嵌入式平台上的重大胜利。
2) 由于队列是一个向量,在连续的内存中,这应该利用 CPU 缓存,这在传统的 CPUs 中很常见。
我正在使用 std::queue 来缓冲我的网络(在本例中为 CAN 总线)上的消息。在中断期间,我将消息添加到 "inbox"。然后我的主程序检查每个周期是否队列为空,如果没有则处理消息。问题是,队列被弹出直到为空(它从 while (! inbox.empty())
退出,但下次我将数据推送到它时,它可以正常工作,但旧数据仍然挂在后面。
例如,第一条消息将“1”推送到队列。循环读取
- 1
下一条消息是“2”。下一个阅读是
- 2
- 1
如果我在另一条消息“3”、“4”之前收到两条消息,那么下一条消息将是
- 3
- 4
- 2
- 1
我很困惑。我也在使用 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::vector
,int
头指针和一个 int
尾指针。 google 搜索应该可以找到大量实施此简单算法的示例:
拉取器检查"if head != tail",如果是,则读取queue[head]
中的消息并递增head。增量表示:head=(head+1)%queuesize。拉取器检查递增 tail
(也模队列大小)是否导致 head
,如果是,则队列已满(根据此方法的先决条件,这是不应该发生的事情)。如果不是,则将消息放入队列[tail],并增加 tail.
如果所有这些操作都以正确的顺序完成,净效果将与使用 std::queue
相同,但是:
1) 没有 std::queue
的开销和它使用的堆分配。应该是嵌入式平台上的重大胜利。
2) 由于队列是一个向量,在连续的内存中,这应该利用 CPU 缓存,这在传统的 CPUs 中很常见。