【问题标题】:Different threads access different memory locations concurrently不同的线程同时访问不同的内存位置
【发布时间】:2017-11-09 11:58:12
【问题描述】:

在 C++14 中有这样的句式:

Different threads of execution are always allowed to access (read and modify) different memory locations concurrently, with no interference and no synchronization requirements.

struct S {
    char a;     // memory location #1
    int b : 5;  // memory location #2
    int c : 11, // memory location #2 (continued)
          : 0,
        d : 8;  // memory location #3
    struct {
        int ee : 8; // memory location #4
    } e;
} obj; // The object 'obj' consists of 4 separate memory locations

这意味着我们可以使用两个线程来改变 S s::a 和 S s::b 而无需考虑 S s 的同步?

【问题讨论】:

  • 我很确定位域不会启动新的内存位置,即使它们跨越多个字节并且某些部分与其他字节对齐。请注意,虽然允许将不同的成员视为不同的实体(至少,当它们不是位字段时),但这是一个坏主意,因为虚假共享只会减慢您的程序。
  • 什么是S?我在给定的结构中看不到任何“s”。
  • @Dietmar 这看起来像一个答案,是的,位字段的行为就像你说的那样,除非用: 0明确分隔
  • “作为一种特殊情况,宽度为零的未命名位域指定下一个位域在分配单元边界处的对齐方式”。不确定“分配单元边界”是否意味着“内存位置”。
  • @PasserBy:在讨论数据竞争和位字段的文本中,我没有看到对位字段中的:0 字段进行任何特殊处理。更具体地说,我认为关于数据竞争的文本无论如何都不会谈论内存位置,而是谈论对象或位域。虽然该示例取自内存模型部分,但它似乎并不是数据竞争的特殊情况。

标签: c++ memory


【解决方案1】:

至少从 2014 年的 n4296 开始,第 1.7.3 节:

一个内存位置要么是一个标量类型的对象,要么是一个相邻位域的最大序列,它们都具有 非零宽度。

所以是的,您的直觉似乎是正确的,您可以在不同步的情况下从单独的线程读取和写入它们。

此外,这似乎至少与同一草案中的第 9.6.2 节切线相关:

作为一种特殊情况,宽度为零的未命名位域 指定下一个位域在分配单元边界处的对齐方式

从 2017 年开始,n4659 的第 4.4.3 节和第 12.2.4.2 节分别使用了相同的措辞。

我没有看到 n4296 中 OP 的确切措辞,但这是在第 1.7.3 节中:

两个或多个执行线程(1.10)可以更新和访问单独的内存 位置互不干扰。

【讨论】:

    【解决方案2】:

    你可以吗?

    在某种程度上,是的。但是,如果您需要s 来尊重和访问不同的成员/位置,那么不需要。 (很明显,你不能让另一个线程同时销毁s。)

    你应该吗?

    在这种情况下几乎可以肯定不是。否则,您只是在破坏本应通过摆弄细节来简化设计的封装。

    也就是说,这个原则很重要,还有一个更实际的例子:
    当您拥有一个对象集合时,不同的线程可以对不同的元素进行操作,而无需担心并发问题:如果在集合中添加/删除/移动项目具有适当的线程安全性

    注意

    您可能需要注意机器架构,以确保未对齐的相邻内存位置的线程安全。 (即使硬件可以保护您,这也可能会以性能为代价。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多