我正在阅读n3485中定义的C ++内存模型,它讨论了发布/获取语义,根据我的理解,以及定义given in this blog:
获取语义是一种属性,只能应用于来自共享内存的读取操作,无论是读取 - 修改 - 写入操作还是普通加载。然后该操作被认为是读取。获取语义通过程序顺序中的任何读取或写入操作来防止读取的内存重新排序。
发布语义是一种属性,只能应用于写入到共享内存的操作,无论它们是读取 - 修改 - 写入操作还是普通存储。然后将该操作视为写入释放。释放语义使用在程序顺序之前的任何读取或写入操作来防止写入释放的内存重新排序。
将阻止在当前读/写完成之前或之后重新排序读/写。第一个(获取)将确保当前正在执行的读取不会在其之后的任何读/写重新排序,后者(发布)将确保当前写入未使用之前的读/写操作重新排序它
现在可以说std::mutex::lock
将获取语义并且std::mutex::unlock
基本上具有 release 语义?
在标准中,我可以在
部分找到30.4.1.2互斥体类型[thread.mutex.requirements.mutex]
11同步:对同一对象的先前
unlock()
操作应与(1.10)同步此操作。
根据我的理解,与同步没有在标准中明确定义,但是它似乎是一种在关系之前发生,正在查看在两个之间评估的两个语句但是,根据我对获取/释放语义的理解,这与内存重新排序有很大关系。 与同步也可以称为发布/获取语义?
发布/获取语义是否也适用于加载/存储操作的重新排序以及操作的线程内交错?
在关于内存模型的标准部分中,它主要讨论了两个线程交错的有序关系。这可以解释这是否也适用于内存排序。
任何人都可以澄清吗?
答案 0 :(得分:6)
现在可以说std :: mutex :: lock将具有获取语义,并且std :: mutex :: unlock本质上具有发布语义?
是,这是正确的。
根据我的理解与同步未在标准
中明确定义
那么,理论上第1.10 / 8段可能是为了给出与同步的定义:
某些库调用与另一个线程执行的其他库调用同步。例如,一个 atomic store-release 与从存储中获取其值的同步(29.3)。 [注意:......]
另一方面,这听起来不像是一个非常正式的定义。然而,第1.10 / 10段间接给出了一个更好的,但隐含的更好的方法:
如果
,评估A 评估B之前依赖性排序- A对原子对象M执行释放操作,而在另一个线程中,B执行消耗 对M进行操作并读取由A或
所指示的释放序列中的任何副作用所写的值- 对于某些评估X,A在X之前是依赖性排序的,而X对B具有依赖性。
[注意:关系“依赖于顺序排列”类似于“与...同步”,但使用发布/ - 消耗代替释放/获取。 - 结束注释]
由于“类似于”关系通常是对称的,我会说上面的“ is-dependency-ordered before ”间接提供了一个定义“与同步” - 虽然您可能正确地反对该注释是非规范性的;不过,这似乎是预期的定义。
我对与关系同步的直觉是它发生在一个存储特定值的线程执行的写(原子)操作和 first (原子)之间读取该值的操作。该操作也可能在同一个线程中。
如果两个操作位于不同的线程上,则 synchronize-with 关系会在操作上建立跨线程排序。
在标准中,我可以在
部分找到30.4.1.2互斥体类型[thread.mutex.requirements.mutex]
11同步:对同一对象的先前
unlock()
操作应与(1.10)同步此操作。
对我而言,这似乎与上面给出的解释兼容。具有释放语义(unlock,store)的操作将与获取语义(锁定,加载)的操作同步。
然而,根据我对获取/释放语义的理解,这更多地与内存重新排序有关。同步也可以称为发布/获取语义?
发布和获取语义描述了某些操作的性质; synchronize-with 关系(实际上)是一个 relationship ,它是以明确定义的方式在具有获取或释放语义的操作之间建立的。
所以从某种意义上说,与同步是这些操作的语义的结果,我们使用那些语义来实现指令的正确排序并约束CPU或者可能的重新排序编译器将执行。