问题标签 [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.

0 投票
2 回答
2509 浏览

c++ - C++0x 中的栅栏,一般只保证原子或内存

C++0x 草案有一个栅栏的概念,这似乎与 CPU/芯片级别的栅栏概念非常不同,或者说 linux 内核人员对栅栏的期望。问题是草案是否真的暗示了一个极其受限的模式,或者措辞很差,实际上暗示了真正的围栏。

例如,在29.8 Fences下,它声明如下:

如果存在原子操作 X 和 Y,则释放栅栏 A 与获取栅栏 B 同步,两者都对某个原子对象 M 进行操作,使得 A 在 X 之前排序,X 修改 M,Y 在 B 之前排序,并且 Y 读取值由 X 写入或由假设释放序列中的任何副作用写入的值 X 将在它是一个释放操作时开始。

它使用这些术语atomic operationsatomic object. 草案中定义了这样的原子操作和方法,但是否仅指这些?释放围栏听起来像商店围栏。不能保证在栅栏之前写入所有数据存储栅栏几乎是无用的。类似于加载(获取)围栏和完整围栏。

那么,C++0x 中的栅栏/栅栏是不是适当的栅栏和措辞非常糟糕,或者它们是否像描述的那样受到严格限制/无用?


就 C++ 而言,假设我有这个现有的代码(假设栅栏现在可以作为高级构造使用——而不是说在 GCC 中使用 __sync_synchronize ):

假设 a,b,c 的大小可以在平台上拥有原子副本。上面的意思是c永远不会被赋值9。请注意,我们不在乎线程 B 何时看到a==5,只是在它看到时它也会看到b==9

C++0x 中保证相同关系的代码是什么?


答案:如果您阅读我选择的答案和所有评论,您将了解情况的要点。C++0x 似乎迫使您使用带栅栏的原子,而普通的硬件栅栏没有这个要求。在许多情况下,只要sizeof(atomic<T>) == sizeof(T)和 ,这仍然可以用来替换并发算法atomic<T>.is_lock_free() == true

不幸的是,这is_lock_free不是 constexpr。这将允许它在static_assert. 退化atomic<T>为使用锁通常是一个坏主意:与使用互斥锁设计的算法相比,使用互斥锁的原子算法将存在可怕的争用问题。

0 投票
3 回答
552 浏览

java - 关于Java内存模型的问题

几天前,我提出了一个问题,询问如何使用关键字'volatile',我得到了答案。在此我要再次感谢帮助过我的人。然而,一个关于JMM的新问题出现在我的脑海中,目前我知道有主内存和线程自己独立的缓存(可能有更专业的术语),现在我想知道线程缓存中存储了什么,共享对象引用的副本(对象地址的副本)还是共享对象的副本?例如,我声明一个对象 B b = new B(); b 可以被两个线程访问,那么当线程访问 b 时,是对象引用b 被复制并存储在线程自己的缓存中还是 b 指向的对象被复制并存储在线程自己的缓存中?谢谢。

0 投票
3 回答
6411 浏览

c - C中的字符串常量与字符数组

可能重复:
C 中的 char s[] 和 char *s 有什么区别?

更多的是一般性问题,而不是试图解决某些问题,我一直在阅读 C 编程语言书,他们注意区分

不同之处在于一个是 char 数组,另一个是指向字符串常量的指针。他们说修改 char 数组是可以接受的,但你不应该修改字符串常量,因为它会触发未定义的行为。我的问题是:存储在内存中的字符串常量与 char 数组的存储方式不同吗?为什么我可以修改它

如您所料,最终打印“这是一个字符串常量”。我可以理解它是如何有意义的,因为字符串常量不应最终在运行时被更改,因为它可能会使其他人/您自己在处理您的代码时感到困惑,而不是期望它的价值会改变,但在纯粹的功能方面它有什么问题,可能触发的未定义行为是什么?当 char 数组不会触发时,它会如何机械地适得其反?我只是想知道我是否遗漏了有关字符串常量在内存中的工作方式以及编译器如何看待它们的信息。

0 投票
1 回答
378 浏览

c++ - Qt4 Creator/QMAKE 等效于“-mcmodel=medium” GCC 编译器设置

我正在使用 Qt Creator 在 Linux 上为内存相当密集的 C++ 应用程序创建 GUI。为了让应用程序能够正常运行,编译时必须设置-mcmodel=medium编译器标志,否则应用程序在执行过程中会突然崩溃(尝试在没有它的情况下在 Qt 中编译,结果如预期般崩溃)。如何在.pro文件中设置 GCC 标志以直接处理此问题,或者是否有与此内存模型标志设置等效的 Qt?

注意:我已经尝试过 QMAKE_CXXFLAGS += -mcmodel=medium 并且它似乎不起作用......

更正:QMAKE_CXXFLAGS 方法似乎有效。返回的错误实际上是硬件内存总线错误。

0 投票
2 回答
489 浏览

java - 创建和加入线程时副作用的可见性

当没有同步块和易失性变量时,一个线程执行的写入何时对另一个线程可见?这是一个简化的快速排序示例:

(为了简单起见,假设两个“工作线程”不产生任何额外的线程。)

加入这两个线程是否保证当前线程看到它们的所有副作用?


在相关说明中,如果我在初始分区之前创建线程会发生什么?

两个线程能看到由 引起的副作用partitionForTheFirstTime()吗?换句话说,创建线程是否会产生先发生关系,还是启动线程?

0 投票
8 回答
265196 浏览

c++ - C++11 引入了标准化的内存模型。这是什么意思?它将如何影响 C++ 编程?

C++11 引入了标准化的内存模型,但这究竟意味着什么?它将如何影响 C++ 编程?

这篇文章(由加文克拉克引用赫伯萨特的话)说,

内存模型意味着 C++ 代码现在有一个标准化的库可以调用,而不管编译器是谁制作的,也不管它在什么平台上运行。有一种标准方法可以控制不同线程如何与处理器的内存通信。

“当您谈论在标准中的不同内核之间拆分 [代码] 时,我们正在谈论内存模型。我们将在不破坏人们将在代码中做出的以下假设的情况下对其进行优化,”萨特说。

好吧,我可以记住这个和网上可用的类似段落(因为我从出生就拥有自己的记忆模型:P),甚至可以发布作为其他人提出的问题的答案,但老实说,我不完全理解这个。

C++ 程序员甚至以前也用于开发多线程应用程序,那么它是 POSIX 线程、Windows 线程还是 C++11 线程又有什么关系呢?有什么好处?我想了解底层细节。

我也觉得 C++11 内存模型在某种程度上与 C++11 多线程支持有关,因为我经常看到这两者在一起。如果是,具体是怎样的?为什么它们应该相关?

由于我不知道多线程的内部如何工作,以及内存模型的一般含义,请帮助我理解这些概念。:-)

0 投票
2 回答
9763 浏览

c++ - [[carries_dependency]] 属性是什么意思?

有人能用凡人都能理解的语言来解释吗?

0 投票
2 回答
1261 浏览

c# - 具有释放/获取语义的易失性

从 Java 5 开始,该volatile关键字具有释放/获取语义以使副作用对其他线程可见(包括对非易失性变量的赋值!)。以这两个变量为例:

请注意,这i是一个常规的非易失性变量。想象一下线程 1 执行以下语句:

在稍后的某个时间点,线程 2 执行以下语句:

根据 Java 内存模型,v线程 1 中的写入和线程 2 中的读取v确保线程 2 看到i线程 1 中执行的写入,因此打印值 42。

我的问题是:volatile在 C# 中是否具有相同的发布/获取语义?

0 投票
1 回答
762 浏览

java - 通过 JVM/JIT 插入栅栏指令

Java 内存模型提供了 DRF 保证(数据竞争自由),这意味着当在 Java 的宽松内存模型下执行时,无数据竞争的程序将给出与顺序一致执行相同的行为。我有以下问题:a)给定一个活泼的程序,编译器(非常具体的任何jvm实现)是否进行延迟集分析/线程逃逸分析等以找出需要插入的栅栏指令以使其竞赛-自由的?还是 JIT 是根据它在哪里执行的?

b)如果编译器做到了(在这种情况下为jvm),为什么我们不能只编写活泼的程序,因为编译器无论如何都会将其转换为无竞争的程序?如果编译器有任何方法可以做到这一点(通过插入栅栏使其无竞争),那么如何(有意地)编写活泼的程序,比如java中并发数据结构的一些实现?

c) 或者 jvm 本身不会将 racy 转换为无种族程序的第三种可能性,但存在其他分析可以为我们做到这一点。是这样吗?

0 投票
3 回答
3773 浏览

c++ - `std::kill_dependency` 有什么作用,我为什么要使用它?

我一直在阅读有关新的 C++11 内存模型的信息,并且遇到了该std::kill_dependency功能(第 29.3/14-15 节)。我很难理解为什么我会想要使用它。

我在N2664 提案中找到了一个示例,但没有多大帮助。

它首先显示没有std::kill_dependency. 在这里,第一行将依赖项携带到第二行中,第二行将依赖项携带到索引操作中,然后将依赖项携带到do_something_with函数中。

还有一个例子std::kill_dependency用来打破第二行和索引之间的依赖关系。

据我所知,这意味着索引和调用do_something_with不是在第二行之前排序的依赖项。根据 N2664:

这允许编译器重新排序对 的调用do_something_with,例如,通过执行预测 的值的推测优化a[r2]

为了调用do_something_with该值a[r2]是必需的。如果,假设,编译器“知道”数组被零填充,它可以优化该调用do_something_with(0);并根据其他两条指令重新排序该调用。它可以产生以下任何一种:

我的理解正确吗?

如果do_something_with通过其他方式与另一个线程同步,那么这对于x.load调用和另一个线程的顺序意味着什么?

假设我的理解是正确的,还有一件事困扰着我:当我编写代码时,什么原因会导致我选择杀死依赖项?