-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;
    }    
};