【问题标题】:gcc optimisation effect on loops with apparently constant variablegcc 对具有明显恒定变量的循环的优化效果
【发布时间】:2017-10-27 17:55:37
【问题描述】:

我在优化一个c++代码时遇到了一种情况,可以简化如下。

考虑这段代码:

#include <iostream>
#include <thread>

using namespace std;

bool hit = false;

void F()
{
   this_thread::sleep_for(chrono::seconds(1));
   hit = true;
}

int main()
{
   thread t(F);

   while (!hit)
      ;

   cout << "finished" << endl;
   t.join();
   return 0;
}

这基本上会启动一个线程,该线程会在一秒钟后将hit 的值更改为true。同时,代码进入一个空循环,该循环将一直持续到hit 的值变为true。我用gcc-5.4 使用-g 标志编译了这个,一切都很好。代码将输出finished 并结束。但是后来我用-O2标志编译它,这一次代码无限卡在循环中。

查看反汇编,编译器生成了以下内容,这就是死循环的根本原因:

jmp 0x6ba6f3 ! 0x00000000006ba6f3

好的,很明显,编译器已经推断出hit 的值是false,它不会在循环中改变,所以为什么不假设它是一个无限循环而不考虑另一个线程可能会改变它的值!并且这种优化模式是在更高级别添加的(-O2)。由于我不完全是优化标志专家,谁能告诉我他们中的哪一个对这个结果负责,所以我可以把它关掉?并且关闭它会对其他代码段产生任何重大的性能成本吗?我的意思是,这种代码模式有多罕见?

【问题讨论】:

  • 使用std::atomic&lt;bool&gt;
  • 如果将hit 声明为易失性会发生什么?
  • @Sinapse:不,实际上,它没有。它只会让症状消失 - 现在。麻烦的是,它仍然是未定义的行为,如果您更改一行代码,优化器可能会做出一些新的决定。
  • @MSalters 我大致理解了这个问题, volatile 解决的只是编译器的优化!但是由于 bool(1 字节)在读/写时不会面临撕裂,而 cache coherence 在上面的示例中并不重要(它只会导致循环超出实际需要的部分),我们很高兴在这种情况下进行当然
  • @Sinapse:标准在这一点上非常明确。这不是“撕裂”或“缓存一致性”,标准没有谈到这一点。对像这样必须这样的单个变量的两次访问是有序的,以未定义行为为代价。 volatile 不会影响排序,也不会治愈未定义的行为。就标准而言,每个线程都可以获得自己的volatile bool hit

标签: c++ multithreading gcc optimization


【解决方案1】:

此代码具有未定义的行为。您正在从一个线程修改 hit 并从另一个线程读取它,但没有同步。

hit 优化为false 是未定义行为的有效结果。您可以通过将hit 设置为std::atomic&lt;bool&gt; 来解决此问题。这使得 if 定义明确,并阻止优化。

【讨论】:

  • 是的,这也可以解决问题(我认为 volatile 会更有效地解决我的问题)但是 OMG !当您将变量定义为原子时,编译器是如何知道的?!我的意思是 volatile 有意义,因为您要添加一个限定符,但在 std::atomic 的情况下,编译器将如何推断它可能在另一个线程中发生变化??
  • 猜猜看! std::atomic&lt;bool&gt; 类中有 volatile 成员。 :) 尝试从 g++ 包含文件夹中打开“原子”文件,您可以在那里看到它们。
  • 不错,值得!
  • @Milack27:实施细节。
【解决方案2】:

如果您想同时从多个线程读取/写入hit,那么您需要某种同步,否则您将引入竞争条件。您可以将hit 设为std::atomic&lt;bool&gt; 或添加在访问hit 值时需要锁定的mutex。如果您只想等待线程完成其工作,则可以只留下thread.join()(并在其后打印“完成”)而不引入任何其他标志。

【讨论】:

    【解决方案3】:

    通过将hit 声明为易失性,您是在告诉编译器此变量可以随时被外部因素修改,因此编译器不会假定它的值不会随着您的main 函数而改变.

    只要只有一个线程写入hit 变量,您的代码应该可以正常工作,不涉及竞争条件。但是,当您处理多个线程时,使用同步工具(如原子对象、互斥锁和信号量)总是更安全,正如此处其他答案中已经提到的那样。

    【讨论】:

    猜你喜欢
    • 2015-04-01
    • 1970-01-01
    • 2017-09-21
    • 2012-02-09
    • 2020-03-08
    • 2020-07-27
    • 1970-01-01
    • 2011-10-04
    • 1970-01-01
    相关资源
    最近更新 更多