【发布时间】:2015-01-11 04:34:04
【问题描述】:
我正在使用 gcc 为单处理器 32 位微控制器编写代码。
我需要使用链表中的时间戳对象。可能是异步的另一部分代码(可能在 ISR 中)将它们添加到列表中。
临界区是通过关闭中断并使用barrier()函数来实现的。
我很困惑 gcc 优化可能会通过缓存指向列表项(下一个要删除的最近项、列表头或空闲列表)的指针来破坏我的代码。我不希望 while 循环中的任何内容从循环周围的前一个时间缓存。内存屏障会保护我免受编译器决定在函数开始时加载一次指针并且不再重新加载它吗?所有这些列表指针都可能在生产者代码的关键部分(未显示)中进行修改。例如,我试图了解pqueue_first 是否应该是一个易失性指针。
大概,如果没有循环(添加到列表就是这种情况),如果函数中的所有代码都在关键部分,我就可以了?
请不要仅仅因为我已经阅读了很多关于易失性或关键部分的通用文章而指向我,但我无法了解如何将其应用于此特定代码。我知道 volatile 确保编译器每次引用它时都会重新加载变量。但我不了解可能的优化范围及其与内存屏障的交互。
typedef struct {
EV_EventQueueEntry_t *pqueue_alloc; // allocation (never changes)
EV_EventQueueEntry_t *pqueue_head; // head of active queue (ISR can change it)
EV_EventQueueEntry_t *pqueue_free; // head of free list (ISR can change it)
EV_EventQueueEntry_t *pqueue_first; // soonest item in queue (ISR can change it)
EV_EventQueueEntry_t *pqueue_first_prev; // back pointer from soonest item (ISR can change it)
EV_UInt_t max_event_count;
} EV_EventQueue_t;
void RunLoop(EV_EventQueue_t *pev)
{
while(not timeout)
{
// Enter critical section
disable_interrupts();
barrier();
// item with most recent timestamp
// this can be changed by ISR add to queue operation
EV_EventQueueEntry_t *pfirst = pev->pqueue_first;
if(pfirst!=NULL && EV_PortIsFutureTime(pfirst->event.timestamp, EV_PortGetTime()))
{
// Copy out message
EV_Event_t e = pfirst->event;
// Remove event from queue
if(pev->pqueue_first_prev != NULL)
pev->pqueue_first_prev->pnext = pfirst->pnext;
else
pev->pqueue_head = pfirst->pnext;
// Put event back on free list
pfirst->pnext = pev->pqueue_free;
pev->pqueue_free = pfirst;
pfirst->event.message.type = EV_MESSAGE_NULL;
// Find next soonest message to process after this one
pev->pqueue_first = ...;
pev->pqueue_first_prev = ...; // back pointer
// Exit critical section
barrier();
enable_interrupts();
// Dispatch message
...
}
else
{
// Exit critical section
barrier();
enable_interrupts();
// waste some time
...
}
}
}
【问题讨论】:
-
我要问的第一个问题是
barrier函数是否为所有处理器和操作系统定义/标准化。如果不是,那么第二个问题是:您正在使用的特定处理器和操作系统的官方文档在哪里。 -
屏障函数似乎输出
__asm__ __volatile__ ("": : :"memory"),如下面的答案所示。这是 AVR32。 -
注:貌似在屏障内很久了。
标签: c volatile producer-consumer critical-section memory-barriers