是在实践中有用的释放序列的概念
Is the concept of release-sequence useful in practice?
c 原子语义仅保证由最后一个线程执行的内存操作的可见性(通过偶然的关系(,该线程执行了释放写入(简单或读取模型 - write(操作。p>考虑
int x, y;
atomic<int> a;
线程1:
x = 1;
a.store(1,memory_order_release);
线程2:
y = 2;
if (a.load(memory_order_relaxed) == 1))
a.store(2,memory_order_release);
然后,a == 2
的观察意味着线程2操作的可见性(y == 2
(,而不是线程1(一个人甚至无法读取x
(。
据我所知,多线程的真实实现使用了栅栏的概念(有时是发行商店(,但在序列或发行序列之前不进行,这是高级C 概念;我看不到这些概念映射到的真实硬件详细信息。
当a
中2中的值2时,实际实现如何不保证线程1内存操作的可见性?
换句话说,发布序列定义中有什么好处吗?为什么发行序列不扩展到修改顺序中的每个后续修改?
特别考虑愚蠢的线程3:
if (a.load(memory_order_relaxed) == 2))
a.store(2,memory_order_relaxed);
愚蠢的线程3可以抑制任何真实硬件的任何可见性保证吗?换句话说,如果Value 2在全球可见,将如何再次使其在全球范围内打破任何订购?
我的真实多处理的心理模型不正确?可以在某些CPU上看到部分可见的值,但请注意另一个值?
(当然,我假设一个放松写作的非疯狂语义,正如及时回到及时的写作,使C 的语言语言绝对是毫无意义的,与诸如Java这样的安全语言不同,它总是具有有限的语义。-Causal放松语义。(
让我们首先回答您的问题:
为什么发行序列不扩展到修改顺序中的每个后续修改?
因为如果是这样,我们将失去一些潜在的优化。例如,考虑线程:
x = 1; // #1
a.store(1,memory_order_relaxed); // #2
根据当前规则,编译器能够重新排序#1和#2。但是,在发布发布序列之后,不允许编译器重新排序这两行,因为另一个线程像线程2这样的线程可能会引入以#2为首并以释放操作为尾声的释放序列,因此有些读取可能会读取 - 另一线程中的操作将与#2同步。
您给出一个特定的例子,并声称所有实施将产生特定的结果,而语言规则不能保证这一结果。这不是问题,因为语言规则旨在处理所有情况,而不仅仅是您的特定示例。当然,语言规则可以得到改进,以便可以保证您的特定示例的预期结果,但这不是一件琐碎的工作。至少,正如我们上面提到的那样,仅扩展发布序列的定义不是一个可接受的解决方案。
- <random>在实践中应该实际使用哪个随机数引擎? std::mt19937?
- std::is_convertible 和 std::convertible_to 之间的区别(在实践中)?
- 在实践中,在运行时为零的乘法中是否有任何"lazy"评估
- 如何控制或优化或删除或释放 UNION 中未使用的内存
- P1008("prohibit aggregates with user-declared constructors")在实践中什么时候有用?
- 无锁原子在实践中是无地址的
- clang的"-Ofast"选项在实践中有什么作用,特别是对于与gcc的任何差异?
- 是在实践中有用的释放序列的概念
- 在现代C 不良实践中,原始指针的使用是
- 仅在64位释放模式中的位移位非法指令
- 大整数增加,我知道理论..在实践中仍然生锈
- 删除向量的第一个元素并释放C++中的内存
- c++释放priority_queue中的内存
- 为什么在实践中向右移动在霓虹灯和SSE中向左移动(反之亦然)
- vector clear()似乎无法释放push_back中分配的内存
- 在实践中,无序映射真的比映射快吗
- 释放函数中的内存
- 释放 C++ 中指针成员的动态内存
- 调用析构函数以释放C++运算符中的内存的正确方法是什么
- 标准库在实践中如何实现哈希表