【发布时间】:2022-08-18 15:10:48
【问题描述】:
是否始终保证读取到本地 volatile 变量?
我有一个对结构成员执行一些操作的函数。结构成员不是易失性的,并且在函数运行时可能会发生变化(嵌入式应用程序、中断)。如果值在读取期间发生变化(复制到局部变量),这没有问题,但在执行多个 if 语句时它们不应发生变化。
#include <string.h>
#include <stdio.h>
typedef struct {
int wptr;
int rptr;
} rw_t;
void
use_it(const rw_t* rw) {
volatile int r, w;
/* It is OK if rw->rptr or rw->wptr get changed during these copy operation */
r = rw->rptr;
w = rw->wptr;
/* I must ensure that r and w are actually local references,
therefore a copy to local shall be done first */
if (r > w) {
printf(\"R is more than W\\r\\n\");
} else if (r < w) {
printf(\"W is more than R\\r\\n\");
} else {
printf(\"R and W are equal\\r\\n\");
}
}
使用-Os 使用 ARM-GCC none-eabi 10.2.1 进行编译似乎可以正常工作。但这是否保证始终适用于任何编译器和任何优化?
最小可复制示例:https://godbolt.org/z/nvocrsrzE
-
看起来您真正想要的是将参数声明为 volatile 指针:
void use_it(const volatile rw_t *rw)... -
\"结构成员不是易失性的,并且在函数运行时可能会改变(嵌入式应用程序、中断)。\" --> 所以这些成员是易挥发的没有
volatile,没有atomic?然后代码在撒谎,r = rw->rptr;冒着 UB 的风险,因为在阅读rw->rptr;时没有原子保护。请详细说明“如果值在读取过程中发生变化(复制到局部变量)”是正确的。 -
@chux 如果 CPU 需要多条指令从内存中读取变量并且它在中间被中断并且新值被加载(在中断例程中)到实际内存中,这没关系,我们可以使用旧值或新值(取决于它何时被打断了)。真正重要的是,在所有
if-elseif-else语句中,r和w不会改变。因此,无论优化设置如何,我都必须确保变量真正被复制到局部变量中。 -
我真的无法理解。在
r = rw->rptr;和w = rw->wptr;之后,r和w都是本地的副本.这意味着无论rw成员发生什么,r和w的值都不会改变。如果rw->w的值在r = rw->rptr;和w = rw->wptr;之间变化,您最多可以有一个竞争条件。但是如果没有一点同步(例如互斥锁),这是无法解决的。 -
@tilz0R 我认为您可以保证
r, w在if()期间不会改变。然而,仍然是狡猾的任务r = rw->rptr; w = rw->wptr;。
标签: c