11

我正在阅读 n3485 中定义的 C++ 内存模型,它讨论了释放/获取语义,据我了解,以及此博客中给出的定义:

获取语​​义是一个只能应用于从共享内存读取的操作的属性,无论它们是读-修改-写操作还是普通加载。然后将该操作视为读取-获取。Acquire 语义可防止读取-acquire 的内存重新排序,以及按照程序顺序跟随它的任何读取或写入操作。

释放语义是一个只能应用于写入共享内存的操作的属性,无论它们是读-修改-写操作还是普通存储。然后该操作被认为是写释放。释放语义防止写释放的内存重新排序,任何读或写操作在程序顺序之前。

将防止在当前读/写完成之前或之后对读/写进行重新排序。第一个(获取)将确保当前正在完成的读取不会被任何读/写重新排序,后者(发布)将确保当前写入不会被之前的读/写操作重新排序它。

现在可以说std::mutex::lock将具有获取语义并且std::mutex::unlock本质上具有释放语义吗?

在标准中,我可以在部分下找到它

30.4.1.2 互斥体类型 [thread.mutex.requirements.mutex]

11 同步:unlock()对同一对象的先前操作应(1.10)此操作同步。

据我了解,标准中没有明确定义同步,但是它似乎是一种发生在关系之前查看两个不同线程之间正在评估的两个语句的类型,但是,根据我对获取/释放语义的理解,这有更多与内存重新排序有关。 同步也可以称为释放/获取语义?

那么释放/获取语义是否不仅适用于加载/存储操作的重新排序,也适用于操作的线程内交错?

在关于内存模型的标准部分中,它主要讨论的是两个线程交错的有序关系。这对于这是否也适用于内存排序有待解释。

有人可以澄清吗?

4

1 回答 1

7

现在可以说 std::mutex::lock 将具有获取语义,而 std::mutex::unlock 本质上具有释放语义吗?

的,这是正确的。

据我了解,标准中没有明确定义同步

好吧,理论上第 1.10/8 段可能是为了给出synchronizes with的定义:

某些库调用与另一个线程执行的其他库调用同步。例如,原子存储释放与从存储(29.3)获取其值的加载获取同步。[笔记: ...]

另一方面,这听起来不像是一个非常正式的定义。然而,第 1.10/10 段间接给出了一个更好的,虽然是隐含的:

评估 A在评估 B之前是依存排序的,如果

— A 对原子对象 M 执行释放操作,并且在另一个线程中,B 对 M 执行消耗操作并读取以 A 为首的释放序列中的任何副作用写入的值,或

— 对于某些评估 X,A 在 X 之前是依赖排序的,并且 X 携带对 B 的依赖。

[注意:关系“之前依赖排序”类似于“同步于”,但使用释放/消耗代替释放/获取。——尾注]

由于“类似于”关系通常是对称的,所以我会说“ is-dependency-ordered before ”的上述定义也间接提供了“同步于”的定义——尽管您可能正确地反对笔记是非- 规范;不过,这似乎是预期的定义。

我对与关系同步的直觉是,它发生在由一个存储某个值的线程执行的写入(原子)操作和读取该值的第一个(原子)操作之间。该操作也可能在同一个线程中。

如果这两个操作在不同的线程上,那么synchronizes-with关系会在操作上建立跨线程排序。

在标准中,我可以在部分下找到它

30.4.1.2 互斥体类型 [thread.mutex.requirements.mutex]

11 同步:unlock()对同一对象的先前操作应(1.10)此操作同步。

对我来说,这似乎与上面给出的解释兼容。具有释放语义(解锁、存储)的操作将与获取语义(锁定、加载)的操作同步。

但是,根据我对获取/释放语义的理解,这更多地与内存重新排序有关。同步也可以称为释放/获取语义?

释放和获取语义描述了一些操作的性质;synchronizes-with关系(实际上)是在具有获取或释放语义的操作之间以明确定义的方式建立的关系。

所以从某种意义上说,同步是这些操作语义的结果,我们使用这些语义来实现指令的正确排序,并限制 CPU 或编译器可能执行的重新排序。

于 2013-03-09T17:50:59.590 回答