问题标签 [memory-model]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c++ - x86 架构的内存排序限制
在他的伟大著作“C++ Concurrency in Action”中,Anthony Williams 写道(第 309 页):
例如,在 x86 和 x86-64 架构上,原子加载操作总是相同的,无论是标记为 memory_order_relaxed 还是 memory_order_seq_cst(参见第 5.3.3 节)。这意味着使用宽松的内存排序编写的代码可以在具有 x86 架构的系统上运行,而在具有更细粒度的内存排序指令集(例如 SPARC)的系统上可能会失败。
我是否理解在 x86 架构上所有原子加载操作都是正确的memory_order_seq_cst
?此外,在cppreference std::memory_order
站点上提到,在 x86 上发布-获取排序是自动的。
如果此限制有效,那么这些排序是否仍适用于编译器优化?
java - java:带有getter和setter的`volatile`私有字段
volatile
我们是否应该像在多个线程中使用实例一样声明私有字段?
在Effective Java中,有一个示例,如果没有 volatile,代码将无法工作:
解释说
被优化为这样的东西:
所以后台线程看不到进一步的修改stopRequested
,所以它永远循环。(顺便说一句,该代码在没有volatile
JRE7 的情况下终止。)
现在考虑这个类:
和一个线程如下:
上面的代码在不使用 volatile 的情况下按预期工作:
我认为由于 public setter,编译器/JVM 永远不应该优化调用的代码getField()
,但是这篇文章说有一些“Volatile Bean”模式(模式#4),应该应用于创建可变线程安全类. 更新:也许那篇文章仅适用于 IBM JVM?
问题是:JLS 的哪一部分明确或隐含地说必须将具有公共 getter/setter 的私有原始字段声明为volatile
(或者它们不必声明)?
抱歉问了一个很长的问题,我试图详细解释这个问题。如果有不清楚的地方,请告诉我。谢谢。
.net - 代码应该对 CPU 内存模型做出哪些假设,以及如何记录这些假设?
根据我的阅读,英特尔处理器架构强制执行比 .net 实现所需提供的更强大的内存模型。代码在多大程度上利用英特尔处理器做出的保证是合适的,或者代码应该在多大程度上添加英特尔实现不需要的内存屏障,以防代码迁移到一个较弱的平台记忆模型?定义一个带有方法的静态类是否合适,例如“如果使用弱内存模型,则执行内存屏障”,并要求代码酌情与该库的“强模型”或“弱模型”版本链接?或者,是否可以在程序启动时使用反射来生成这样一个静态类,这样 JIT 编译器可以在使用强模型时,“
如果我有我的 druthers,.net 将提供MemoryLock
具有一些半锁操作的类的变体,这将要求所有持有半锁的线程都必须遵守该半锁的内存模型。在具有非常强大的内存模型的系统中,半锁不会做任何事情。在内存模型非常弱的系统中,任何希望进入已经有另一个线程的半锁的线程都必须等到第一个线程退出,或者它可以被 CPU 或内核调度(基于根据半锁指定的模型)第一个线程正在使用。请注意,与普通锁不同,aMemoryLock
永远不会死锁,因为任何冲突的锁定要求的组合都可以通过调度所有线程在同一个 CPU 上运行来解决,并且系统可以释放MemoryLock
由死掉的线程持有的任何线程(因为这样做的目的MemoryLock
是保护资源不被访问以违反内存模型的方式,死线程当然不能进行此类访问)。
当然,从 .net 4.0 开始就不存在这样的东西了;鉴于此,处理确实存在的情况的最佳方法是什么?将专为更强的内存模型设计的代码迁移到具有更弱模型的系统,在没有一些方法来强制执行更强的模型的情况下,将是灾难的根源,但是添加大量Lock
或MemoryBarrier
对于代码的原始目标平台而言,不必要的调用似乎不是很吸引人。我所知道的强制使用强内存模型的代码的唯一方法是让每个线程设置其 CPU 亲和性。如果有一种方法可以设置一个进程选项,这样 .net 一次只能使用一个内核,那可能会很有用(特别是如果它意味着 JIT 可以用更快的非总线锁定等价物代替总线锁定互锁操作) ,但我知道设置 CPU 亲和性的唯一方法是限制程序将特定选定的 CPU 用于其所有线程,即使该 CPU 被其他应用程序负载过重并且其他一些 CPU 处于空闲状态。
附录
考虑以下代码:
据我了解,即使没有内存屏障,在英特尔处理器上运行的代码也能保证写入不会被重新排序;因此,在线程 2 中,被读取的人要么是“Smiley”、“George”,要么是“Simpson”、“Bart”。然而,.net 内存模型比这更弱,.net 程序可能会发现自己运行在线程 2 可能会看到不完整对象的处理器上(因为写入SharedPerson
可能发生在写入之前newPerson.FirstName
)。在 at 添加内存屏障MaybeMemoryBarrier1
可以避免这种危险,但无论是否实际需要内存屏障,都会有性能成本。
我认为最低要求的 .net 内存模型不会那么弱,以至于在保证线程 2在读取自身之前MaybeMemoryBarrier2
永远不会访问所引用的对象的情况下需要(如上面代码中的情况,因为新实例在存储到 ) 之前不会暴露给任何外部代码。另一方面,假设情况略有变化,因此创建了一条记录,然后将其放入队列中(假设队列本身所有必要的锁和内存屏障);之后,处理器会:SharedPerson
SharedPerson
SharedPerson
Thread 2
JobInfo
Thread 1
如果线程 1 有内存屏障,但线程 2 没有,是否可以保证当线程 2 看到JobInfo
它创建的记录出现在 中时CurrentJob
,它会正确读取其StartTime
字段(并且不会看到缓存或部分缓存的值从Thread 2
操纵那个物体的时候开始?
arm - ARM 弱内存模型保证了哪些排序
我了解弱记忆模型和强记忆模型的基本区别。但是弱的没有确切的定义,它取决于架构(这里是 ARM)。
我已经浏览了 ARM 信息中心的文档,但仍然不清楚很多事情。有人可以列出 -
任何能够解释黑白 ARM 和 PPC(Power PC)内存模型差异的人都可以获得奖励积分。
c++ - C++ 编译器如何支持 C++11 原子,但不支持 C++11 内存模型
在查看 Clang 和 g++ C++11 实现状态时,我注意到一些奇怪的事情:
它们支持 C++11 原子,但它们不支持 C++11 内存模型。
我的印象是你必须有 C++11 内存模型才能使用原子。那么对原子和内存模型的支持到底有什么区别呢?
缺乏内存模型支持是否意味着使用std::atomic<T>
arent seq 的合法 C++11 程序一致?
参考资料:
http ://clang.llvm.org/cxx_status.html
http://gcc.gnu.org/gcc-4.7/cxx0x_status.html
linux - 如何在 BSD 或 Linux 中控制程序的默认堆栈设置?
假设我有一个正在运行的程序,我查看BSD中的/proc/[pid]/map (或 linux 中的/proc/[pid]/maps),我会看到如下一行:
这是堆栈。我所有的 PC-BSD 程序都使用相同的堆栈边界 0xbfc00000。在 Linux 上,关闭 ASLR 后,也会发生类似的事情。
我想在某些程序上使用这些设置,但堆栈似乎甚至没有在 elf 程序头或节头中指定。
因此,如果我想更改设置,例如:
- 更改堆栈的执行权限
- 将堆栈边界设置为另一个值
有没有办法更改单个程序的“堆栈设置”?系统范围如何?
x86 - 内存重新排序:可以将加载与较早的存储重新排序到不同但包含的位置吗?
在英特尔的处理器手册:第 8.2.3.4 节中的链接中,声明可以将负载重新排序,早期存储到不同位置,但不能将早期存储重新排序到相同位置。
所以我明白以下两个操作可以重新排序:
并且以下两个操作不能重新排序:
但是当存储和负载位于不同的位置时会发生什么,但负载完全包含存储,例如:
那么在这种情况下'y'可以为0吗?
编辑(@Hans Passant)为了进一步解释这种情况,我试图看看我是否可以使用这种技术在不使用锁定指令的情况下设计一种线程之间的准同步。
所以一个更具体的问题是,给定一个全局变量:
两个线程执行以下代码:
线程 1:
线程 2:
'y' 可以为两个线程都为 1 吗?
注意:__builtin_popcountl 是内置的 gcc 内在函数,用于计算变量中设置的位数。
java - 如何理解happens-before一致
在JLS 的第 17 章中,引入了一个概念:happens-before 一致。
如果对于 A 中的所有读取 r,一组动作 A 在发生之前是一致的,其中 W(r) 是 r 看到的写入动作,但不是 hb(r, W(r)) 或存在在 A 中存在写入 w 使得 wv = rv 和 hb(W(r), w) 和 hb(w, r)"
在我的理解中,它等于下面的话:……,既不是……也不是……
所以我的前两个问题是:
- 我的理解正确吗?
- “wv = rv”是什么意思?
它还给出了一个例子:17.4.5-1
在第一个执行顺序中:
命令本身已经告诉我们两个线程是交替执行的,所以我的第三个问题是:左数是什么意思?
据我了解,r2 和 r1 都可以看到初始写入 0 的原因是 A 和 B 都不是 volatile 字段。所以我的第四个问题是:我的理解是否正确?
在第二个执行顺序中:
根据happens-before一致性的定义,不难理解这个执行顺序是happens-before一致(如果我的第一个理解是正确的)。所以我的第五个和第六个问题是:现实世界中是否存在这种情况(读后写)?如果是这样,你能给我一个真实的例子吗?
java - 正确同步的程序是否仍然允许数据竞争?(第一部分)
JLS有两个结论:
- C1:如果一个程序没有数据竞争,那么该程序的所有执行将看起来是顺序一致的:
data-race-free => sequentially consistent
- C2:如果一个程序正确同步,那么该程序的所有执行将看起来是顺序一致的:
correctly synchronized => sequentially consistent
如果 C1 的反义词为真,那么我们可以得出结论:
- C3:如果一个程序正确同步,那么它就没有数据竞争:
correctly synchronized => data-race-free
但遗憾的是,JLS 中并没有这样的说法,所以我得出第四个结论:
- C4:一个程序可以正确同步并且有数据竞争。
但我对这种方法并不满意,我想证明这个结论是正确的(或错误的),即使是以非正式的方式或样本方式。
首先,我认为显示包含数据竞争的多线程程序的顺序一致执行的代码段有助于理解和解决这个问题。
经过认真考虑,我仍然找不到合适的样品。那么请给我这样的代码段好吗?