为什么全局变量会对函数调用中的编译器优化造成麻烦?

ben

http://www.hpl.hp.com/techreports/2004/HPL-2004-209.pdf

为了防止编译器将内存操作移至对诸如pthread Mutex之类的函数的调用lock(),它们实际上被视为对不透明函数的调用,编译器对此不了解任何信息。编译器有效地假设pthread互斥锁lock()可以读取或写入任何全局变量。因此,不能简单地在调用中移动内存引用。这种方法还确保以适当的方式或多或少地适当地处理传递调用(例如f(),对随后调用pthread互斥锁的函数的调用)lock(),即f(),无论整个用户程序是否执行,内存操作都不会跨该调用移动马上被分析。

为什么会这样呢?为什么引用不能移动的任何反例?

布赖恩

编译器可以自由移动代码。(略有简化)要求是没有可见的副作用。

本文介绍了为什么需要在编译器级别而不是库级别支持线程。因此,让我们考虑一下编译器正在优化代码时的含义。我将从Kerrek SB的出色示例开始,因为此回复对于评论太长。

int x = 0;
pthread_mutex_lock(&m);
x = y;

优化器看到的值不会被修改,但会被设置两次。copmiler可以访问该函数内部的代码,并且看不到任何东西可以修改赋值。由于没有可见的副作用,优化器可以消除分配给零的值,而只需将其替换为y的值即可。优化器将其删除,将其转换为:

pthread_mutex_lock(&m);
int x = y;

这可能不会影响任何东西,变量x是局部变量,没有其他影响。

现在让我们做一个更具问题的人为例子。

if(globals.hasData) {
  int prelock_value = globals.foo;
  pthread_mutex_lock(&m);
  if(prelock_value != globals.foo) {
    // value changed before we could lock it, do something different
    DoSpecialStuffSinceValueChangedWhileWaiting();
    pthread_mutex_unlock(&m);
    return;
  }
  DoOtherStuff();
  ...

因此,现在我们将从优化器的角度进行研究。优化程序会看到您读取了一个值,然后执行了一些不会修改该值的操作,然后针对刚存储的值进行了测试。由于看不到可见的副作用,因此可能会像这样删除比较:

if(globals.hasData) {
  int prelock_value = globals.foo;
  pthread_mutex_lock(&m);
  if( false /* always false: prelock_value != globals.foo */ ) {
    // value changed before we could lock it, do something different
    DoSpecialStuffSinceValueChangedWhileWaiting();
    pthread_mutex_unlock(&m);
    return;
  }
  DoOtherStuff();
  ...

然后,它看起来再次删除了无效代码。由于if的结果始终为false,因此它会看到对整数的不必要分配,不必要的条件,并得出以下结果

if(globals.hasData) {
  pthread_mutex_lock(&m);
  // everything was removed.
  DoOtherStuff();

如果将其与原始函数进行比较,则可以很清楚地看出这根本不是程序员想要的。

这些年来,已经发现了大量潜在的优化方法。他们中的许多人都假设将代码从一个地方安全移到另一个地方的安全性,或者假设值仅由该代码块修改。这些假设在并行编程中可能会严重破坏。

优化器需要了解某些功能不能移动,并且某些功能会成为无法跨越的障碍,否则会使优化器的假设无效。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

为什么编译器将全局变量限制为始终由常量值初始化?

来自分类Dev

为什么C和C ++编译器将显式初始化和默认初始化的全局变量放在不同的段中?

来自分类Dev

为什么在全局变量的析构函数中调用thread.join失败

来自分类Dev

为什么 Elixir 编译器不会对某些“不可匹配”的函数发出警告?

来自分类Dev

什么决定全局变量的内存地址。编译器还是操作系统?

来自分类Dev

jQuery:为什么在函数内部调用函数时函数返回全局变量?

来自分类Dev

为什么C ++编译器没有优化未使用的参考变量?

来自分类Dev

为什么变量不是全局变量但函数是可以的?

来自分类Dev

为什么更新全局变量在导入函数中定义的函数中不起作用

来自分类Dev

编译器优化忽略循环中无效的函数调用

来自分类Dev

编译器可以优化多个相同的函数调用吗

来自分类Dev

pygame中的全局变量麻烦

来自分类Dev

为什么构造函数中的全局变量和参数变量不能具有相同的名称?

来自分类Dev

编译器决定调用函数“ POW”,而不是在编译时对其求值。为什么?

来自分类Dev

编译器优化是否可以消除在for循环的条件中反复调用的函数?

来自分类Dev

我可以让编译器优化结构中的函数调用吗?

来自分类Dev

为什么编译器没有优化此负载

来自分类Dev

为什么编译器优化会破坏我的代码?

来自分类Dev

为什么编译器不优化中断代码?

来自分类Dev

为什么编译器在 C++11 中给出消息“重载函数的调用不明确”?

来自分类Dev

在 JavaScript 中,为什么这个全局变量在我的函数中未定义?

来自分类Dev

为什么我的函数不将值返回全局变量?

来自分类Dev

为什么导入函数定义的全局变量不改变?

来自分类Dev

为什么VS 2015编译器无法在abs()实现中优化浮点数的分支?

来自分类Dev

为什么在BGE Python中变量不是全局变量

来自分类Dev

为什么在函数中无法访问我的全局变量?

来自分类Dev

为什么我无法读取嵌套函数中全局变量的变化?

来自分类Dev

为什么全局变量不会随同一个全局变量中的全局函数一起更新?安卓/Java

来自分类Dev

Java优化编译器中的临时变量

Related 相关文章

  1. 1

    为什么编译器将全局变量限制为始终由常量值初始化?

  2. 2

    为什么C和C ++编译器将显式初始化和默认初始化的全局变量放在不同的段中?

  3. 3

    为什么在全局变量的析构函数中调用thread.join失败

  4. 4

    为什么 Elixir 编译器不会对某些“不可匹配”的函数发出警告?

  5. 5

    什么决定全局变量的内存地址。编译器还是操作系统?

  6. 6

    jQuery:为什么在函数内部调用函数时函数返回全局变量?

  7. 7

    为什么C ++编译器没有优化未使用的参考变量?

  8. 8

    为什么变量不是全局变量但函数是可以的?

  9. 9

    为什么更新全局变量在导入函数中定义的函数中不起作用

  10. 10

    编译器优化忽略循环中无效的函数调用

  11. 11

    编译器可以优化多个相同的函数调用吗

  12. 12

    pygame中的全局变量麻烦

  13. 13

    为什么构造函数中的全局变量和参数变量不能具有相同的名称?

  14. 14

    编译器决定调用函数“ POW”,而不是在编译时对其求值。为什么?

  15. 15

    编译器优化是否可以消除在for循环的条件中反复调用的函数?

  16. 16

    我可以让编译器优化结构中的函数调用吗?

  17. 17

    为什么编译器没有优化此负载

  18. 18

    为什么编译器优化会破坏我的代码?

  19. 19

    为什么编译器不优化中断代码?

  20. 20

    为什么编译器在 C++11 中给出消息“重载函数的调用不明确”?

  21. 21

    在 JavaScript 中,为什么这个全局变量在我的函数中未定义?

  22. 22

    为什么我的函数不将值返回全局变量?

  23. 23

    为什么导入函数定义的全局变量不改变?

  24. 24

    为什么VS 2015编译器无法在abs()实现中优化浮点数的分支?

  25. 25

    为什么在BGE Python中变量不是全局变量

  26. 26

    为什么在函数中无法访问我的全局变量?

  27. 27

    为什么我无法读取嵌套函数中全局变量的变化?

  28. 28

    为什么全局变量不会随同一个全局变量中的全局函数一起更新?安卓/Java

  29. 29

    Java优化编译器中的临时变量

热门标签

归档