- 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/
我有这个代码 var myChart = new FusionCharts("../themes/clean/charts/hbullet.swf", "myChartId", "400", "75
既然写入是立即进行的(复制到内核缓冲区并返回),那么使用 io_submit 进行写入有什么好处? 事实上,它 (aio/io_submit) 看起来更糟,因为您必须在堆上分配写入缓冲区并且不能使用基
我正在使用 mootool 的 Request.JSON 从 Twitter 检索推文。收到它后,我将写入目标 div 的 .innerHTML 属性。当我在本地将其作为文件进行测试时,即 file:
最终,我想将 Vertica DB 中的数据抓取到 Spark 中,训练机器学习模型,进行预测,并将这些预测存储到另一个 Vertica DB 中。 当前的问题是确定流程最后部分的瓶颈:将 Spark
我使用 WEKA 库编写了一个 Java 程序, 训练分类算法 使用经过训练的算法对未标记的数据集运行预测 将结果写入 .csv 文件 问题在于它当前写出离散分类结果(即算法猜测一行属于哪个类别)。我
背景 - 我正在考虑使用 clickonce 通过 clickonce(通过网站)部署 WinForms 应用程序。相对简单的应用程序的要素是: - 它是一个可执行文件和一个数据库文件(sqlite)
是否有更好的解决方案来快速初始化 C 数组(在堆上创建)?就像我们使用大括号一样 double** matrix_multiply(const double **l_matrix, const dou
我正在读取 JSON 文件,取出值并进行一些更改。 基本上我向数组添加了一些值。之后我想将其写回到文件中。当我将 JSONArray 写回文件时,会被写入字符串而不是 JSONArray 对象。怎样才
我为两个应用程序使用嵌入式数据库,其中一个是服务器,另一个是客户端。客户端应用程序。可以向服务器端发送获取数据请求以检索数据并显示在表格(或其他)中。问题是这样的:如何将获取的数据保存(写入)到页面文
是否有更好的解决方案来快速初始化 C 数组(在堆上创建)?就像我们使用大括号一样 double** matrix_multiply(const double **l_matrix, const dou
从问题得出问题:找到所有 result = new ArrayList(); for (int i = 2; i >(i%8) & 0x1) == 0) { result.add(i
由于某种原因,它没有写入 CSV。谁能明白为什么它不写吗? def main(): list_of_emails = read_email_csv() #read input file, cr
关闭。 这个问题是 not reproducible or was caused by typos 。它目前不接受答案。 这个问题是由于错别字或无法再重现的问题引起的。虽然类似的问题可能在这里出现,
我目前正在开发一个保存和加载程序,但我无法获得正确的结果。 编写程序: #include #include #define FILENAME "Save" #define COUNT 6 type
import java.io.*; public class Main2 { public static void main(String[] args) throws Exception {
我需要使用预定义位置字符串“Office”从所有日历中检索所有 iOS 事件,然后将结果写入 NSLog 和 UITextView。 到目前为止,这是我的代码: #import "ViewCo
我正在尝试将 BOOL 值写入 PFInstallation 中的列,但会不停地崩溃: - (IBAction)pushSwitch:(id)sender { NSUserDefaults *push
我以前在学校学过一些简单的数据库编程,但现在我正在尝试学习最佳实践,因为我正在编写更复杂的应用程序。写入 MySQL 数据库并不难,但我想知道让分布式应用程序写入 Amazon EC2 上的远程数据库
是否可以写回到ResourceBundle?目前我正在使用 ResourceBundle 来存储信息,在运行时使用以下内容读取信息 while(ResourceBundle.getBundle("bu
关闭。这个问题是not reproducible or was caused by typos .它目前不接受答案。 这个问题是由于错别字或无法再重现的问题引起的。虽然类似的问题可能是on-topi
我是一名优秀的程序员,十分优秀!