在多线程或RTOS环境中,这些代码是否完全相同?
我相信他们不是。但是第一个代码绝对保存在多线程环境中吗?编译器是否有规则为'ga'分配一个寄存器,以后在func_a()中不会再读'ga'?
我知道我可以使用锁,但这不是关于如何保护数据的问题。这只是关于编译器行为的问题。
// ga是一个全局变量。
int func_a() {
int a = ga;
return a>2 ? a-2 : 2-a;
}
int func_b() {
return ga>2 ? ga-2 : 2-ga;
}
我的目的是寻找一种标准方式(不是平台特定的)来只读取一次ga并将其值赋给局部变量'a'。
无论“ga”是否发生变化,都可以始终如一地使用“a”。答案 0 :(得分:2)
这些版本的代码在执行函数的多个线程面前都有未定义的行为。当然,不同的编译器可以在将全局变量保存到寄存器中时做不同的事情。更重要的是,无法保证分配到局部变量可以相对于改变全局变量的线程以原子方式完成。
答案 1 :(得分:2)
C标准中没有规则要求编译器以不同方式实现这些功能。例如使用寄存器时,编译器可能会也可能不会“优化”从ga
到a
的分配(即通过'优化',我的意思是:将ga
加载到REG中,然后使用相同的REG来完成剩余的计算,将其用作a
)。或者它可能不会这样做。
如果要实现无锁数据结构:
如果您使用的是C99,则需要:
在这个答案的早期版本中,我提到了一个方面问题(与volatile
有关,而且与你的真实无关问题):
有一个案例可以限制func_b
的实施方式,但我实际上是在切线:如果ga
被声明为volatile
。< / p>
如果ga
是易变的,那么ga
上的每次读取都必须重新从内存中加载ga
。即在func_b
中,ga
将从内存中加载两次。一旦进行比较,一次计算返回值。例如,预期的用途是ga
指的是内存映射的I / O端口。然后,如果ga
的值在两次读取之间发生变化,则这将反映在返回值中。但是,如果您在另一个线程中更改ga
,请不要指望理智/定义的行为。
另一方面,不拥有volatile
限定符并不意味着ga
只能在func_b
中读取一次{{1}}。并且没有限定词是“与易变性相反的”。
答案 2 :(得分:0)
行为取决于您使用的编译器,每个编译器都有自己的优化规则。
答案 3 :(得分:0)
这两个片段可能会以相同的机器代码结束。在多线程情况下,它们都不安全。
volatile
会强制创建一个临时变量,但由于从“ga”到volatile变量的副本不能保证是原子的,所以这不是线程安全的。
编写此类代码的唯一安全方法是使用警卫:
int func_a() {
mtx_lock(&ga_mutex);
int a = ga;
mtx_unlock(&ga_mutex);
return a>2 ? a-2 : 2-a;
}