函数调用未排序修改全局变量是否引发UB?加mutex能否解决?
未指定顺序函数调用与未定义行为的问题解答
一、原始代码是否存在未定义行为(UB)
先看原始代码:
int counter = 0; int mul_func(int x) { counter *= x; x = counter; return x; } int add_func(int x) { counter += x; x = counter; return x; } int main(void) { int sum = add_func(3) + mul_func(2); }
这段代码不存在未定义行为,仅存在未指定行为:
- C标准规定,表达式中函数调用的执行顺序是未指定的,编译器可选择先执行
add_func(3)再执行mul_func(2),或者反过来。 - 单线程下两个函数的执行是原子的,不会出现交错修改全局变量
counter的情况,最终只会产生两种确定的合法结果:- 先执行
add_func:counter变为3,再执行mul_func将counter乘2得到6,sum = 3 + 6 = 9 - 先执行
mul_func:counter乘以2仍为0,再执行add_func将counter加3得到3,sum = 0 + 3 = 3
未指定行为仅导致结果不确定,但程序行为完全符合标准约束,不属于未定义行为。
- 先执行
二、添加互斥锁后的效果
先修正代码中的两处错误:pthread_mutex_d应为pthread_mutex_t,pthread_mutex_init需传入属性参数(可传NULL使用默认属性),修正后的代码如下:
#include <pthread.h> int counter = 0; pthread_mutex_t mtx; int mul_func(int x) { pthread_mutex_lock(&mtx); counter *= x; x = counter; pthread_mutex_unlock(&mtx); return x; } int add_func(int x) { pthread_mutex_lock(&mtx); counter += x; x = counter; pthread_mutex_unlock(&mtx); return x; } int main(void) { pthread_mutex_init(&mtx, NULL); int sum = add_func(3) + mul_func(2); pthread_mutex_destroy(&mtx); }
在单线程场景下,添加互斥锁不会解决任何问题(也不会引入问题):
- 互斥锁的作用是解决多线程下的数据竞争,但这段代码是单线程执行,本来就不存在数据竞争。
- 函数调用的顺序依然是未指定的,编译器仍可选择先执行任意一个函数,最终结果依然是之前的两种可能之一。
- 这段代码不存在未定义行为,结果的不确定性依然是未指定行为导致的,而非UB。
三、无数据竞争的“未排序”是否会引发UB
明确结论:不会。
- 未指定顺序的函数调用(单线程下),只要没有数据竞争(单线程天然不存在数据竞争),且没有违反C标准的其他规则(比如对同一个对象的无同步读写),那么程序的行为就是标准允许的——只是结果取决于编译器选择的执行顺序,但每种可能的结果都是合法的,不属于未定义行为。
- 未定义行为是指标准完全放弃对程序行为的约束(比如可能崩溃、输出无意义结果等),而未指定行为只是结果不确定,但程序的每一种可能行为都在标准的约束范围内。
内容的提问来源于stack exchange,提问作者D.J. Elkind
相关产品推荐
相关产品推荐

