首页 文章

C内存模型 - 此示例是否包含数据竞争?

提问于
浏览
12

我正在阅读Bjarne Stroustrup 's C++11 FAQ and I' m,无法理解memory model部分中的示例 .

他提供了以下代码段:

// start with x==0 and y==0
if (x) y = 1; // thread 1
if (y) x = 1; // thread 2

FAQ说这里没有数据竞争 . 我不明白 . 内存位置 x 由线程1读取并由线程2写入而没有任何同步(对于 y 也是如此) . 那's two accesses, one of which is a write. Isn'那个数据的定义是什么?

此外,它说“每个当前的C编译器(我所知道的)给出了正确答案 . ”这个正确答案是什么?根据一个线程的比较是在另一个线程的写入之前还是之后发生(或者另一个线程的写入是否对读取线程可见),答案可能不同?

5 回答

  • 6
    // start with x==0 and y==0
    if (x) y = 1; // thread 1
    if (y) x = 1; // thread 2
    

    既然x和y都不是真的,另一个也不会被设置为真 . 无论执行指令的顺序如何,(正确的)结果总是x保持为0,y保持为0 .

  • 2

    内存位置x由线程2写入

    是真的吗?你为什么这么说?

    如果 y 为0,那么 x 不会被线程2写入 . 并且 y 从0开始 . 同样, x 不能为非零,除非某种方式 y 非零"before"线程1运行,并且这不可能发生 . 这里的一般观点是条件写入不会导致数据竞争 .

    不过,这是内存模型的一个重要事实,因为不允许线程编译的编译器(假设 y 不是易失性的)将代码 if (x) y = 1; 转换为 int tmp = y; y = 1; if (!x) y = tmp; . 然后会有一场数据竞赛 . 我可以't imagine why it would want to do that exact transformation, but that doesn'重要的是,非线程环境的优化器可以做违反线程内存模型的事情 . 因此,当Stroustrup说他所知道的每个编译器给出了正确的答案时(在C 11 's threading model, that is), that'之下,这是一个关于C 11线程编译器准备就绪的非平凡陈述 .

    if (x) y = 1 的更现实的转换将是 y = x ? 1 : y; . 我认为这会导致您的示例中的数据竞争,并且在分配标准中没有特殊处理 y = y ,这使得在另一个线程中读取 y 时执行不安全是安全的 . 你可能会发现很难想象硬件不那么现实但却有明显的数据竞争 .

  • 14

    必须有写入的总顺序,因为没有线程可以写入变量 xy ,直到某个其他线程首先将 1 写入任一变量 . 换句话说,您基本上有三种不同的场景:

    • thread 1会写入 y ,因为 x 是在 if 语句之前的某个位置写入的,然后如果线程2稍后出现,它会向 x 写入 1 的相同值,并且't change it'的前一个值 1 .

    • thread 2可以写入 x ,因为 yif 语句之前的某个时刻被更改了,然后线程 1 将写入 y ,如果它稍后出现 1 的相同值 .

    • 如果只有两个线程,则跳过 if 语句,因为 xy 保持为0 .

  • -2

    这两种写法都没有发生,因此没有竞争 . x和y都保持为零 .

    (这是在讨论幻像写的问题 . 假设一个线程在检查条件之前推测性地写了这个,然后尝试纠正之后的事情 . 这会打破另一个线程,所以不允许这样做 . )

  • 3

    内存模型设置了代码和数据区域的可支持大小 . 在比较链接源代码之前,我们需要指定内存模型,即可以设置数据和代码的大小限制 .

相关问题