- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
GCC 编译这个:
#include <atomic>
std::atomic<int> a;
int b(0);
void func()
{
b = 2;
a = 1;
}
func():
mov DWORD PTR b[rip], 2
mov DWORD PTR a[rip], 1
mfence
ret
mov dword ptr [rip + b], 2
mov eax, 1
xchg dword ptr [rip + a], eax
ret
最佳答案
我将您的示例放在 Godbolt compiler explorer, and added some functions 上以读取、增加或组合( a+=b
)两个原子变量。我还使用了 a.store(1, memory_order_release);
而不是 a = 1;
以避免获得比需要更多的订单,因此它只是 x86 上的一个简单存储。
有关(希望正确)的解释,请参见下文。 更新 :我将 "release" semantics 与 StoreStore 屏障混淆。我想我修正了所有错误,但可能留下了一些错误。
首先是简单的问题:
Is the write to ‘a’ guaranteed to be an atomic?
a
的线程都将获得旧值或新值,而不是一些写入一半的值。这个
happens for free on x86 和大多数其他体系结构具有适合寄存器的任何对齐类型。 (例如,在 32 位上不是
int64_t
。)因此,在许多系统上,这恰好适用于
b
,大多数编译器生成代码的方式。
std::atomic
当然可以保证任何必要的对齐。
a+=3
进行 1000 次评估将始终产生
a += 3000
。如果
a
不是原子的,你可能会得到更少。
</rant>
Is any other thread reading ‘a’ as 1 guaranteed to read ‘b’ as 2.
std::atomic
提供的保证。
a = 1
提升出一个也写入
b
的循环。)
Why does the MFENCE happen after the write to ‘a’ not before.
b
再存储到
a
来实现源代码排序。
MFENCE
,这是一个完整的屏障,包括 StoreLoad (
the only kind x86 doesn't have for free 。(
LFENCE/SFENCE
只对弱排序操作有用)x25313340
movnt
的 ARM32 asm 是:
# get pointers and constants into registers
str r1, [r3] # store b=2
dmb sy # Data Memory Barrier: full memory barrier to order the stores.
# I think just a StoreStore barrier here (dmb st) would be sufficient, but gcc doesn't do that. Maybe later versions have that optimization, or maybe I'm wrong.
str r2, [r3, #4] # store a=1 (a is 4 bytes after b)
dmb sy # full memory barrier to order this store wrt. all following loads and stores.
b=2; a=1;
,但加载和存储总是首先有寄存器操作数,第二个是内存操作数。如果您习惯于 x86,这真的很奇怪,其中内存操作数可以是大多数非 vector 指令的源或目标。加载立即数也需要很多指令,因为固定的指令长度只为
op dest, src1 [,src2]
(move word)/
movw
(move top) 的有效载荷留下了 16b 的空间。
movt
and release
命名来自锁:
acquire
是一个完整的屏障(包括 StoreLoad),但 ARM64 具有加载链接/存储条件的加载-获取/存储-释放版本,用于执行原子读-修改-写。据我了解,即使锁定,这也避免了对 StoreLoad 屏障的需要。
lock xadd
类型的写入相对于源代码中的所有其他内存访问(加载和存储)进行排序。您可以控制
std::atomic
的排序。
std::memory_order
。
a
包括这个和更多。
store(memory_order_release)
只是所有商店的单向 StoreStore 屏障。 x86 免费提供 StoreStore,因此编译器所要做的就是将存储按源顺序排列。
std::atomic_thread_fence(memory_order_release)
使您的代码在弱序 ISA 上更高效。
a.load(std::memory_order_acquire)
,我认为它被包含在内的部分原因是它分别具有所有屏障类型。 (嗯,cppref 网页只提到了订购商店,而不是 LoadStore 组件。虽然它不是 C++ 标准,所以也许完整标准说得更多。)
#LoadStore | #StoreStore
对于这个用例来说不够强大。
This post 谈论您使用标志来指示其他数据已准备就绪的情况,并谈论
memory_order_consume
。
memory_order_consume
的指针,甚至是指向结构或数组的指针,则
consume
就足够了。但是,没有编译器知道如何进行依赖项跟踪以确保它在 asm 中以正确的顺序放置东西,因此当前的实现总是将
b
视为
consume
。这太糟糕了,因为除 DEC alpha(和 C++11 的软件模型)之外的每个架构都免费提供这种排序。
According to Linus Torvalds, only a few Alpha hardware implementations actually could have this kind of reordering, so the expensive barrier instructions needed all over the place were pure downside for most Alphas.
acquire
语义(一个 StoreStore 屏障),以确保在更新指针时新的有效负载可见。
release
编写代码并不是一个坏主意,如果您确定自己理解其含义并且不依赖于
consume
不能保证的任何内容。将来,一旦编译器变得更智能,即使在 ARM/PPC 上,您的代码也将在没有障碍指令的情况下编译。实际的数据移动仍然必须在不同 CPU 上的缓存之间发生,但在弱内存模型机器上,您可以避免等待任何不相关的写入可见(例如生产者中的暂存缓冲区)。
consume
代码 ,因为当前的编译器为您提供了比代码请求更强的排序。
memory_order_consume
中发现的 gcc 错误,在 x86 上产生了 b=2; a.store(1, MO_release); b=3;
,而不是 0x23131313181a=1;b=3
用于 b=3; a=1;
,并且可能使用更少的 mcc 进行 x86 gcc 操作。我不确定每个存储之间是否需要 dmb sy
来保护信号处理程序免于做出错误假设,或者这是否只是缺少优化。 a=1; a=1;
用于使用“流式”写入的数据,如 mfence
或 0x2341 或 123341 (NT = 非时间性)。除了绕过缓存,x86 NT 加载/存储具有弱排序语义。 关于c++ - 原子操作、std::atomic<> 和写入顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32384901/
有没有办法用连词创建原子 if ?也就是说,我可以以某种方式在 C 中自动测试 if(A && B) 吗?如果它在第一个连接处短路,那么没问题,但如果没有短路,则在检查 B 时,A 可能已更改。有什么
我有很多 fork 的过程。子进程做很多事情和另一个系统调用。 当任何子进程从系统调用中获取错误时,它会将错误描述打印到 stderr 并将 SIGUSR1 发送到组长(主要父进程)。 SIGUSR1
阅读 boost::atomic 上的文档和 std::atomic 让我感到困惑的是 atomic 是否接口(interface)应该支持非平凡类型? 也就是说,给定一个只能通过将读/写包含在一个完
我有一个命令,可以将叠加图像放在视频上。 之后,我调整输出大小以适合某些尺寸。 通常一切正常,但有时且仅在某台台式计算机上,当第二次精化开始时,命令返回错误:moov atom not found 让
我最近发现当 LANG 设置为 C.utf8 时,X11 原子 WM_NAME 未在 Swing JFrame 中设置。但为 LANG 的其他值设置。这发生在带有 OpenJDK 11.0.9 的 L
我目前正在使用blackmagic的prorecorder录制视频。我使用 ffmpeg 将视频即时转码为 mp4 视频容器。持续时间未知,因为我正在对 prorecorder 输出到命名管道的 .t
这里真的有人使用 atom 来处理 git 提交消息吗?我想但我遇到了这个问题并且一直坚持使用 git commit -m '....' 。当我尝试使用 atom 时,它会打开 atom,我几乎立即从
考虑: void foo() { std::vector> foo(10); ... } foo 的内容现在有效吗?或者我是否需要显式循环并初始化它们?我检查过 Godbolt,看起来不错,但
在official FAQ我阅读的 Memcached: “发送到 memcached 的所有单独命令都是绝对原子的。” 然而,当涉及到 get_multi 和 set_multi 时,我仍然不清楚。
在测试程序的可扩展性时,我遇到了必须将 memcpy 操作设置为原子操作的情况。我必须将 64 字节的数据从一个位置复制到另一个位置。 我遇到了一种解决方案,即使用旋转变量: struct recor
我对 C++ 原子变量感到困惑。如果我有一个原子 x,我想在一个线程中递增并在另一个线程中读取,我可以执行++x 还是必须执行 x.atomic_fetch_add(1)。在读者线程中,我可以做类似
跟进自 Multiple assignment in one line ,我很想知道这对原子数据类型是如何工作的,特别是 bool 类型的例子。 给定: class foo { std::at
我想创建一个版本控制系统,并且对版本号为 1 的新条目的查询如下所示: ID 和修订号组合起来就是主键。 insert into contentfile (id, name, revision, ac
我在 iOS 项目中有下一个独立的测试片段: /// ... std::atomic_bool ab; ab.store(true); bool expected = false; while (!a
我了解如何使用条件变量(此构造的名称很糟糕,IMO,因为 cv 对象既不是变量也不表示条件)。所以我有一对线程,canonically使用 Boost.Thread 设置为: bool awake =
因此,对于最终项目,我尝试制作一款包含三种不同 meteor 的游戏;铜牌、银牌和金牌。虽然青铜阵列在Setup()中工作正常,但银色和金色 meteor 由于某种未知原因而高速移动。 functio
第一个问题,为什么不在 atomic_compare_exchange_weak 操作的参数中应用后缀求值 (++)?运算前后a的值相同。然而,当在 printf() 中使用时,正如预期的那样,该值会
我正在尝试使用 OpenMP 对已经矢量化的代码进行内部函数并行化,但问题是我使用一个 XMM 寄存器作为外部“变量”,我会在每个循环中递增。现在我正在使用 shared 子句 __m128d xmm
clojure“atom”的文档指出 - "Changes to atoms are always free of race conditions." 但是,竞争条件不仅根据更改定义,而且在不同线程中
我一直在研究原子引用计数的实现。 库之间的大多数操作都非常一致,但我在“减少引用计数”操作中发现了惊人的多样性。 (请注意,通常情况下,shared 和 weak decref 之间的唯一区别是调用了
我是一名优秀的程序员,十分优秀!