众所周知,由于使用了写缓冲区,x86体系结构没有实现顺序一致性内存模型,因此-
在《内存一致性和一致性入门》中,我们可以阅读到关于总存储顺序(TSO)内存一致性模型中的读-修改-写(RMW)操作(该模型应该与x86非常相似):
... 我们认为RMW是紧接着存储的负载。由于TSO的排序规则,RMW的加载部分无法通过早期加载。起初,RMW的加载部分可能会通过写入缓冲区中的早期存储,但这是不合法的。如果RMW的加载部分通过较早的存储,那么RMW的存储部分也必须通过较早的存储,因为RMW是原子对。但由于TSO中不允许存储相互传递,因此RMW的加载部分也不能传递较早的存储。
好的,原子操作必须是原子操作,即RMW访问的内存位置在RMW操作期间不能被其他线程/内核访问,但如果原子操作的早期存储通过加载部分与RMW访问的内存位置无关,那会怎么样?假设我们有以下几条指令(伪代码):
store int32 value in 0x00000000 locathtml" target="_blank">ion
atomic increment int32 value in 0x10000000 location
第一个存储被添加到写入缓冲区并等待轮到它。同时,原子操作从另一个位置(即使在另一个缓存行中)加载值,传递第一个存储,并在第一个存储之后将存储添加到写入缓冲区中。在全局内存顺序中,我们将看到以下顺序:
负载(原子的一部分)-
是的,从性能的角度来看,这可能不是最好的解决方案,因为我们需要将原子操作的缓存线保持在读写状态,直到提交写缓冲区中的所有先前存储,但是,撇开性能考虑,是否存在任何违反TSO内存一致性模型的情况?我们是否允许RMW操作的加载部分将早期存储传递到不相关的位置?
因为我们需要将原子操作的缓存线保持在读写状态,直到提交写缓冲区中的所有先前存储,但是,性能考虑除外
如果你在执行与L阻止的操作性质相同的操作S时持有锁L,即存在S'可以被L阻止(延迟)并且S可以被L阻止(延迟)',那么你就有死锁的配方,除非你被保证是唯一这样做的参与者(这将使整个原子事情毫无意义)。
对于不同地址的任何存储加载对,您可以问同样的问题:由于无序执行,加载可能在内部比旧存储更早执行。在X86中,这是允许的,因为:
可以使用旧商店将货物重新排序到不同的位置,但不能使用旧商店将货物重新排序到相同的位置
(来源:英特尔64架构内存订购白皮书)
但是,在您的示例中,lock perfix会阻止这种情况发生,因为(来自同一组规则):
锁定的指令有一个总订单
这意味着锁会强制执行内存屏障,例如m栅栏(实际上一些编译器使用锁定操作作为栅栏)。这通常会使CPU停止加载的执行,直到存储缓冲区耗尽,迫使存储首先执行。
我读过,x86的INC指令不是原子指令。我的问题是为什么会这样?假设我们在x86-64上递增一个64位整数,我们可以用一条指令来递增,因为INC指令同时处理内存变量和寄存器。那么为什么它不是原子的呢?
初始化数据段 BSS 堆栈 堆 代码 现在考虑以下程序: 在上面的程序中,arr和x都是在main函数内本地声明的。我认为这意味着它们都将在函数堆栈上分配空间。但是,当我在linux上运行size命令时,我发现实际上正在为数组分配数据段中的空间。
问题内容: Java集合仅存储对象,而不存储原始类型。但是,我们可以存储包装器类。 为什么会有这种约束? 问题答案: 这是一个Java设计决策,有人认为这是一个错误。容器需要对象,而基元不是从对象派生的。 这是.NET设计人员从JVM中学到的地方,并实现了值类型和泛型,因此在许多情况下都无需装箱。在CLR中,通用容器可以将值类型存储为基础容器结构的一部分。 Java选择在编译器中100%添加通用支
如EhCache留档所述: 实际上,这意味着持久性内存中缓存将启动,其所有元素都将在磁盘上。[...]因此,Ehcache设计不会在启动时将它们全部加载到内存中,而是根据需要懒惰地加载它们。 我希望内存缓存启动时将所有元素都存储在内存中,我该如何实现? 这是因为我们的网站对缓存执行了大量的访问,所以我们第一次访问网站时,它的响应时间非常长。
为什么会这样?最后,还有其他类似的功能我应该知道是不允许的。
本文向大家介绍char 型变量中能不能存储一个中文汉字,为什么?相关面试题,主要包含被问及char 型变量中能不能存储一个中文汉字,为什么?时的应答技巧和注意事项,需要的朋友参考一下 char 类型可以存储一个中文汉字,因为Java中使用的编码是Unicode(不选择任何特定的编码,直接使用字符在字符集中的编号,这是统一的唯一方法),一个char 类型占2个字节(16 比特),所以放一个中文是没问