我有一段代码:
#include <iostream>
#include <thread>
long int global_variable;
struct process{
long int loop_times_ = 0;
bool op_;
process(long int loop_times, bool op): loop_times_(loop_times), op_(op){}
void run(){
for(long int i=0; i<loop_times_; i++)
if (op_) global_variable+=1;
else global_variable-=1;
}
};
int main(){
struct process p1(10000000, true);
struct process p2(10000000, false);
std::thread t1(&process::run, p1);
std::thread t2(&process::run, p2);
t1.join();
t2.join();
std::cout <<global_variable<< std::endl;
return 0;
}Main函数触发两个线程,增加和减少一个全局变量。如果我用以下方式编译:
g++ -std=c++11 -o main main.cpp -lpthread每次执行都会得到不同的输出。但是,如果我添加-O3并使用以下内容进行编译:
g++ -O3 -std=c++11 -o main main.cpp -lpthread每次输出都是零。
这里发生了什么样的优化,消除了我的关键部分,我如何才能欺骗编译器而不对其进行优化?
编辑: OS: Ubuntu16.04.4,g++:5.4.0
发布于 2017-03-14 15:29:09
很可能您的run方法正在被优化为相当于:
void run(){
if (op_) global_variable += loop_times_;
else global_variable -= loop_times_;这是编译器可以很容易地用可用的信息做的事情。
要欺骗编译器,您必须确保循环不会在每次迭代中添加或减去1,而不会产生其他副作用。
尝试在循环中添加一个函数调用,这只会在名为totalIterationsDone的对象上增加一个简单的计数器,或者类似的。这可能会迫使编译器实际执行循环。将循环变量作为参数传递也可能迫使它跟踪i的中间值。
struct process{
long int loop_times_ = 0;
bool op_;
long int _iterationsDone = 0;
process(long int loop_times, bool op): loop_times_(loop_times), op_(op){}
void run(){
for(long int i=0; i<loop_times_; i++){
if (op_) global_variable+=1;
else global_variable-=1;
Trick(i);
}
}
void Trick(int i){
_iterationsDone += 1;
}
};发布于 2017-03-14 15:06:17
您的程序有未定义的行为,以数据竞赛的形式出现。两个线程在没有同步的情况下访问一个变量是一种数据竞争,因此没有定义。
删除数据竞争的最简单方法是使global_variable成为原子化的:
std::atomice<long int> global_variable;代码的其余部分不需要做进一步的更改。
https://stackoverflow.com/questions/42789511
复制相似问题