繁体   English   中英

使用“指向volatile的指针”是否始终阻止编译器优化?

[英]Does using “pointer to volatile” prevent compiler optimizations at all times?

问题在于: 您的程序暂时使用了一些敏感数据,并希望在不再需要时删除它 在自身上使用std::fill()并不总是有用 - 编译器可能会决定以后不访问内存块,因此擦除它是浪费时间并消除擦除代码。

用户ybungalobill建议使用volatile关键字

{
  char buffer[size];
  //obtain and use password
  std::fill_n( (volatile char*)buffer, size, 0);
}

目的是在看到volatile关键字时,编译器不会尝试消除对std::fill_n()的调用。

volatile关键字总会阻止编译器从这种内存修改代码中消除吗?

从最后的C ++ 0x草案[intro.execution]:

8对符合要求的实施的最低要求是:

- 严格根据抽象机的规则来评估对易失性对象的访问。

[...]

12访问由volatile glvalue(3.10)指定的对象,修改对象,调用库I / O函数或调用执行任何这些操作的函数都是副作用,[...]

因此,即使您提供的代码也不能进行优化。

编译器可以自由地优化代码, 因为buffer不是易失性对象

标准只要求编译器严格遵守易失性对象的语义。 这是C ++ 03所说的

符合实施的最低要求是:

  • 在序列点处,易失性对象在先前评估完成且尚未发生后续评估的意义上是稳定的。 [...]

抽象机器的可观察行为是它对易失性数据的读写顺序以及对库I / O函数的调用

在您的示例中,您拥有的是使用volatile lvalues对非易失性对象进行读写操作。 C ++ 0x删除了我上面引用的第二个文本,因为它是多余的。 C ++ 0x就是说

符合实施的最低要求是:

  • 严格根据抽象机器的规则来评估对volatile对象的访问。[...]

这些统称为程序的可观察行为

虽然有人可能认为“易变数据”可能意味着“由易失性左值访问的数据”,这仍然相当长,但C ++ 0x措辞消除了对代码的所有疑虑,并明确允许实现对其进行优化。

但正如人们向我指出的那样,在实践中这可能无关紧要。 优化这种事情的编译器很可能会违背程序员的意图(为什么有人会有一个指向volatile的指针),所以可能会包含一个bug。 尽管如此,我还是经验丰富的编译器供应商在他们面临关于他们过度激进的优化的错误报告时引用了这些段落。 最后, volatile是固有的特定平台,你应该仔细检查结果。

您希望删除的内存内容可能已经从CPU /内核的内部缓存刷新到RAM,其他CPU可以继续查看它。 覆盖后,您需要使用互斥/内存屏障指令/原子操作或其他东西来触发与其他内核的同步。 在实践中,你的编译器可能会在调用任何外部函数之前执行此操作(谷歌Dave Butenhof在多线程中使用volatile的可疑实用程序的帖子),所以如果你之后很快就做了线程,那么这不是一个主要问题。 总之:不需要volatile。

一致的实现可以在其闲暇时推迟任何易失性读取和写入的实际性能,直到易失性读取的结果将影响易失性写入或I / O操作的执行。

例如,给出如下内容:

volatile unsigned char vol1,vol2;
extern unsigned char res[1000];
void test(int scale)
{
  unsigned char ch;

  for (int 0=0; i<10000; i++)
  {
    res[i] = i*vol1*scale;
    vol2 = res[i];
  }
}

符合条件的编译器可以根据其选择检查scale是否是128的倍数 - 如果是 - 在从vol1执行任何读取或写入vol2之前清除所有偶数索引的res值。 即使编译器需要在执行以下写入vol2之前从vol1执行每次读取,编译器也可以将两个操作推迟到运行基本上无限量的代码之后。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM