-O3循环增量优化
-O3 loop increment optimization
我有这段代码:
#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:Ubuntu 16.04.4,g++:5.4.0
您的程序有未定义的行为,表现为数据竞争。两个线程在没有同步的情况下访问一个变量是一种数据竞争,因此是未定义的。
消除数据竞争的最简单方法是使 global_variable
原子化:
std::atomice<long int> global_variable;
其余代码无需进一步更改。
很可能您的 运行 方法被优化为等效于:
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;
}
};
我有这段代码:
#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:Ubuntu 16.04.4,g++:5.4.0
您的程序有未定义的行为,表现为数据竞争。两个线程在没有同步的情况下访问一个变量是一种数据竞争,因此是未定义的。
消除数据竞争的最简单方法是使 global_variable
原子化:
std::atomice<long int> global_variable;
其余代码无需进一步更改。
很可能您的 运行 方法被优化为等效于:
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;
}
};