C++ C++;20标准::原子<;浮动>;-标准::原子<;双倍>;。专业
C++20包括C++ C++;20标准::原子<;浮动>;-标准::原子<;双倍>;。专业,c++,multithreading,floating-point,memory-model,stdatomic,C++,Multithreading,Floating Point,Memory Model,Stdatomic,C++20包括原子和原子的专门化。这里有人能解释一下这有什么实际用途吗?我能想象的唯一目的是当我有一个线程在随机点异步更改原子双精度或浮点值,而其他线程异步读取该值时(但在大多数平台上,易失性双精度或浮点值实际上也应该这样做)。但这种需要应该是极其罕见的。我认为这种罕见的情况不能证明将其纳入C++20标准是合理的。编辑:添加乌尔里希·埃克哈特的评论以澄清: 让我试着重新表述一下:即使volatile在一个特定的平台/环境/编译器上做了与atomic相同的事情,一直到生成的机器代码,那么atomi
原子
和原子
的专门化。这里有人能解释一下这有什么实际用途吗?我能想象的唯一目的是当我有一个线程在随机点异步更改原子双精度或浮点值,而其他线程异步读取该值时(但在大多数平台上,易失性双精度或浮点值实际上也应该这样做)。但这种需要应该是极其罕见的。我认为这种罕见的情况不能证明将其纳入C++20标准是合理的。编辑:添加乌尔里希·埃克哈特的评论以澄清:
让我试着重新表述一下:即使volatile在一个特定的平台/环境/编译器上做了与atomic相同的事情,一直到生成的机器代码,那么atomic在保证方面仍然更具表现力,而且,它保证是可移植的。此外,当您可以编写自文档代码时,您应该这样做。” Volatile有时具有以下两种效果:
- 不要依赖于“volatile”,如果“what”不是volatile的最初目的,请做您想做的事情,例如启用外部传感器或DMA更改内存地址而不受编译器干扰
- 如果需要原子,请使用std::atomic李>
- 如果要禁用严格别名优化,请像Linux内核一样,在gcc上禁用严格别名优化李>
- 如果要禁用其他类型的编译器优化,请对ARM或x86_64等使用编译器内部函数或代码显式汇编
- 简而言之,如果标准提供的构造更清晰、更可移植,则不要依赖于编译器和CPU系列相关的行为。如果你认为你的“黑客”比正确的方法更有效,可以使用godbolt.org来比较汇编程序的输出
#include <inttypes.h>
#include <atomic>
std::atomic<uint32_t> sensorval;
//volatile uint32_t sensorval;
uint32_t foo()
{
uint32_t retval = sensorval;
return retval;
}
int main()
{
return (int)foo();
}
对于那些想要X86示例的人,我的同事Angus Lepper慷慨地提供了以下示例:
我能想象的唯一目的是当我有一个线程改变
在随机点和其他点上异步双原子或浮点
线程异步读取这些值
是的,这是原子的唯一用途,不管实际类型如何。它可能是原子的bool
,char
,int
,long
或其他任何东西
无论您对type
有什么用法,std::atomic
都是它的线程安全版本。
无论您对float
或double
有什么用法,std::atomic
都可以以线程安全的方式进行写入、读取或比较
说std::atomic
只有很少的用法实际上是说float/double
有很少的用法。原子的
和原子的
从C++11开始就存在了。atomic
模板适用于任意可复制的T
使用旧的C++11之前版本可以破解的所有东西使用volatile
共享变量可以使用C++11atomic
和std::memory\u order\u relaxed
完成
在C++20之前不存在的是原子RMW操作,如x.fetch\u add(3.14)代码>
或简称x+=3.14
。(不知道为什么不)。这些成员函数仅在原子整数专门化中可用,因此您只能在浮点和双精度上加载、存储、交换和CAS,类似于任意T
类类型
有关如何使用compare\u exchange\u weak
滚动您自己的,以及如何使用(以及纯加载、纯s)的详细信息,请参阅
foo():
push {r4, lr}
ldr r4, .L4
bl __sync_synchronize
ldr r4, [r4]
bl __sync_synchronize
mov r0, r4
pop {r4, lr}
bx lr
.L4:
.word .LANCHOR0
#include <atomic>
volatile double vx;
std::atomic<double> ax;
double px; // plain x
void FP_non_RMW_increment() {
px += 1.0;
vx += 1.0; // equivalent to vx = vx + 1.0
ax.store( ax.load(std::memory_order_relaxed) + 1.0, std::memory_order_relaxed);
}
#if __cplusplus > 201703L // is there a number for C++2a yet?
// C++20 only, not yet supported by libstdc++ or libc++
void atomic_RMW_increment() {
ax += 1.0; // seq_cst
ax.fetch_add(1.0, std::memory_order_relaxed);
}
#endif
FP_non_RMW_increment():
movsd xmm0, QWORD PTR .LC0[rip] # xmm0 = double 1.0
movsd xmm1, QWORD PTR px[rip] # load
addsd xmm1, xmm0 # plain x += 1.0
movsd QWORD PTR px[rip], xmm1 # store
movsd xmm1, QWORD PTR vx[rip]
addsd xmm1, xmm0 # volatile x += 1.0
movsd QWORD PTR vx[rip], xmm1
mov rax, QWORD PTR ax[rip] # integer load
movq xmm2, rax # copy to FP register
addsd xmm0, xmm2 # atomic x += 1.0
movq rax, xmm0 # copy back to integer
mov QWORD PTR ax[rip], rax # store
ret
<source>: In function 'void FP_non_RMW_increment()':
<source>:9:8: warning: compound assignment with 'volatile'-qualified left operand is deprecated [-Wvolatile]
9 | vx += 1.0; // equivalent to vx = vx + 1.0
| ~~~^~~~~~