gpt4 book ai didi

c++ - 理解 C++ 中的 volatile 关键字

转载 作者:行者123 更新时间:2023-11-30 01:01:47 30 4
gpt4 key购买 nike

我想了解 volatile 关键字在 C++ 中的工作原理。

我看过 What kinds of optimizations does 'volatile' prevent in C++? 。查看接受的答案,看起来 volatile 禁用了两种优化

  1. 防止编译器将值缓存在寄存器中。
  2. 当从您的程序的 POV 看来不必要时,优化访问该值。

我在 https://en.cppreference.com/w/cpp/language/as_if 找到了类似的信息。

Accesses (reads and writes) to volatile objects occur strictly according to the semantics of the expressions in which they occur. In particular, they are not reordered with respect to other volatile accesses on the same thread.

我编写了一个简单的 C++ 程序,将数组中的所有值相加,以比较普通 int 与 volatile int 的行为。请注意,部分和不是易变的。

数组由不合格的 int 组成。

int foo(const std::array<int, 4>& input)
{
auto sum = 0xD;
for (auto element : input)
{
sum += element;
}
return sum;
}

数组由 volatile ints 组成

int bar(const std::array<volatile int, 4>& input)
{
auto sum = 0xD;
for (auto element : input)
{
sum += element;
}
return sum;
}

当我查看生成的汇编代码时,SSE 寄存器仅在普通 int 的情况下使用。据我所知,使用 SSE 寄存器的代码既没有优化读取也没有重新排序它们。循环展开,因此也没有分支。我可以解释为什么 codegen 不同的唯一原因是:volatile 读取可以在累积发生之前重新排序吗?显然,sum 不是易变的。如果这样的重新排序不好,是否有可以说明问题的情况/示例?

使用 clang9 生成的代码

foo(std::array<int, 4ul> const&):                # @foo(std::array<int, 4ul> const&)
movdqu (%rdi), %xmm0
pshufd $78, %xmm0, %xmm1 # xmm1 = xmm0[2,3,0,1]
paddd %xmm0, %xmm1
pshufd $229, %xmm1, %xmm0 # xmm0 = xmm1[1,1,2,3]
paddd %xmm1, %xmm0
movd %xmm0, %eax
addl $13, %eax
retq
bar(std::array<int volatile, 4ul> const&): # @bar(std::array<int volatile, 4ul> const&)
movl (%rdi), %eax
addl 4(%rdi), %eax
addl 8(%rdi), %eax
movl 12(%rdi), %ecx
leal (%rcx,%rax), %eax
addl $13, %eax
retq

最佳答案

C++ 中的 volatile 关键字是从 C 继承而来的,它的目的是作为一个通用的包罗万象的方式来指示编译器应该允许读取或写入对象的可能性的地方它不知道的副作用。由于不同平台可能产生的副作用类型会有所不同,因此该标准留下了一个问题,即编译器编写者判断他们应该如何最好地为客户服务。

几十年来,Microsoft 的 8088/8086 和后来的 x86 编译器一直被设计为支持使用 volatile 对象来构建保护“普通”对象的互斥量的做法。举个简单的例子:如果线程 1 做了类似的事情:

ordinaryObject = 23;
volatileFlag = 1;
while(volatileFlag)
doOtherStuffWhileWaiting();
useValue(ordinaryObject);

线程 2 周期性地做类似的事情:

if (volatileFlag)
{
ordinaryObject++;
volatileFlag=0;
}

那么对 volatileFlag 的访问将作为对 Microsoft 编译器的警告,即他们应该避免假设任何对象上的任何先前操作将如何与后面的操作交互。其他语言(如 C#)中的 volatile 限定符遵循此模式。

不幸的是,clang 和 gcc 都没有包含任何以这种方式处理 volatile 的选项,而是选择要求程序员使用特定于编译器的内在函数来产生与 Microsoft 仅使用旨在适合此类目的的标准关键字 volatile [根据标准的作者,“volatile 对象也是多个变量共享的适当模型过程。”--参见 http://www.open-std.org/jtc1/sc22/wg14/www/C99RationaleV5.10.pdf p. 76 岁25-26]

关于c++ - 理解 C++ 中的 volatile 关键字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58252099/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com