- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想了解 volatile 关键字在 C++ 中的工作原理。
我看过 What kinds of optimizations does 'volatile' prevent in C++? 。查看接受的答案,看起来 volatile 禁用了两种优化
我在 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 int
s 组成
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/
这将是一篇很长的文章,为了将其上下文化并提供尽可能多的信息,我必须仔细浏览各种链接和引号——这通常是我们进入 C/C++ 标准兔子洞的唯一方法。如果您对这篇文章有更好的引用或任何其他改进,请告诉我。但
我想知道 volatile 关键字与 register、const 和 static 结合的不同用途关键词。我不确定有什么影响,所以我认为: register volatile int T=10; 建
让我们考虑以下 Java 代码 int x = 0; int who = 1 Thread #1: (1) x++; (2) who = 2; Thread #2 while(who
有一个函数“remove_cv”(http://en.cppreference.com/w/cpp/types/remove_cv)可以删除常量和 volatile 。 我的问题是为什么可以从“con
我正在尝试在下面的“MpscQueue.h”中的嵌入式目标上实现多个生产者(通过中断)、单个消费者(通过应用程序线程)队列。 我想知道我是否可以安全地删除一些 volatile下面的用法(见内联问
我的问题适用于最初为 null 的字段,然后初始化为非 null 值,然后不再更改。 由于该字段需要尽快可供所有线程使用,因此我需要使用 volatile 。 但是,如果我想尽可能避免 volatil
我以前见过几次类似 fld = fld 的东西,但在所有这些情况下,可以消除虚拟写入并获得更好的性能。 public class Tst{ public volatile int fld =
看完this question和 this (尤其是第二个答案)我对 volatile 及其与内存屏障有关的语义感到非常困惑。 在上面的例子中,我们写入了一个 volatile 变量,这会导致一个 m
如下所示,该程序有一个共享 var flag,但不带 volatile : public class T { public static void main(String[] args) {
我明白声明 int *volatile ptr; 表示指针本身是volatile int a=10; int *volatile ptr=&a; 现在 ptr 和 a 都在更新。会不会导致访问ptr时
最近我需要比较两个 uint 数组(一个是 volatile 数组,另一个是非 volatile 数组),结果令人困惑,我一定是对 volatile 数组有一些误解。 我需要从输入设备读取一个数组并将
这两个 C 定义有什么区别? volatile uint32_t *ptr1 = (volatile uint32_t *)0x20040000; volatile uint32_t *ptr1 =
// structure is like this, but not exact formation. class queue { volatile List worksWaiting; }
考虑以下这段代码: struct S{ int i; S(int); S(const volatile S&); }; struct S_bad{ int i; }; vola
在 Windows x64 上,考虑到一些额外的见解,何时允许编译器将 ABI 标记为 volatile 的寄存器视为非 volatile 寄存器?我有一个反汇编函数,其中 r11 用于在函数调用后恢
我对下面的代码段有疑问。结果可能有 [0, 1, 0] 的结果(这是用 JCStress 执行的测试)。那么这怎么会发生呢?我认为应该在写入 Actor2 (guard2 = 1) 中的 guard2
好吧,假设我有一堆变量,其中一个声明为 volatile: int a; int b; int c; volatile int v; 如果一个线程写入所有四个变量(最后写入 v),而另一个线程读取所有
我试图理解为什么这个例子是一个正确同步的程序: a - volatile Thread1: x=a Thread2: a=5 因为存在冲突访问(存在对 a 的写入和读取),所以在每个顺序一致性执行中,
我正在编写一个需要同时支持 volatile 和非 volatile 实例的类( volatile 实例使用原子操作,非 volatile 实例使用常规操作),并且想知道我是否以正确的方式进行处理。到
我正在为 Cortex-M0 CPU 和 gcc 编写代码。我有以下结构: struct { volatile unsigned flag1: 1; unsigned flag2: 1
我是一名优秀的程序员,十分优秀!