gpt4 book ai didi

c - volatile 和非 volatile 位域

转载 作者:太空狗 更新时间:2023-10-29 16:48:06 27 4
gpt4 key购买 nike

我正在为 Cortex-M0 CPU 和 gcc 编写代码。我有以下结构:

struct {
volatile unsigned flag1: 1;
unsigned flag2: 1;

unsigned foo; // something else accessed in main loop
} flags;

flag1 从 GPIO 中断处理程序和主循环中读取和写入。 flag2 仅在主循环中读写。

ISR 看起来像这样:

void handleIRQ(void) {
if (!flags.flag1) {
flags.flag1 = 1;
// enable some hw timer
}
}

主循环是这样的:

for (;;) {
// disable IRQ
if (flags.flag1) {
// handle IRQ
flags.flag1 = 0;
// access (rw) flag2 many times
}
// wait for interrupt, enable IRQ
}

在主循环中访问 flag2 时,编译器是否会优化对它的访问,这样它就不会在每次用代码读取或写入时都被提取或存储到内存中?

我不清楚,因为要在 ISR 中设置 flag1,它需要加载整个 char,设置一个位并将其存储回去。

最佳答案

根据我对 C11 标准的解读,为此使用位域是不合适的 - 即使它们都被声明为 volatile。以下摘自3.14 Memory location :

  1. Memory location
    Either an object of scalar type, or a maximal sequence of adjacent bit-fields all having nonzero width
  2. NOTE 1 Two threads of execution can update and access separate memory locations without interfering with each other.

  3. NOTE 2 It is not safe to concurrently update two non-atomic bit-fields in the same structure if all members declared between them are also (non-zero-length) bit-fields, no matter what the sizes of those intervening bit-fields happen to be.

volatile 没有异常(exception)。因此,如果两个执行线程(即主线程和 ISR)如果 ISR 将更新一个标志而主线程将更新另一个标志,则使用上述位域是不安全的。给出的解决方案是在两者之间添加一个大小为0的成员,以强制将它们放在不同的内存位置。但话又说回来,这意味着两个标志都会消耗至少一个字节的内存,因此再次使用非位域 unsigned charbool 更简单> 对他们来说:

struct {
volatile bool flag1;
bool flag2;

unsigned foo; // something else accessed in main loop
} flags;

现在它们将被放置在不同的内存位置,并且可以在不相互干扰的情况下更新它们。


但是 flag1volatile 仍然是绝对必要的,因为否则更新 flag1没有副作用 在主线程中,编译器可以推断它可以将该字段仅保留在寄存器中 - 或者根本不需要更新任何内容。

但是,需要注意的是,在 C11 下,即使 volatile 的保证也可能不够:5.1.2.3p5 :

When the processing of the abstract machine is interrupted by receipt of a signal, the values of objects that are neither lock-free atomic objects nor of type volatile sig_atomic_t are unspecified, as is the state of the floating-point environment. The value of any object modified by the handler that is neither a lock-free atomic object nor of type volatile sig_atomic_t becomes indeterminate when the handler exits, as does the state of the floating-point environment if it is modified by the handler and not restored to its original state.

因此,如果需要完全兼容,flag1 应该是 volatile _Atomic bool 类型的例子;甚至可以使用 _Atomic 位域。但是,这两者都需要 C11 编译器。

然后,您可以查看编译器的手册,看它们是否保证对此类 volatile 对象的访问也保证是原子的。

关于c - volatile 和非 volatile 位域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42902622/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com