内存模型和并发

Memory Models and Concurrency

我想了解 C/C++ 内存模型,但我在所有文章、博客、youtube 视频中发现 "Memory models are only needed for concurrency"..

任何人都可以向我解释为什么会这样吗?

我知道内存模型是一种抽象,它允许程序员使用编程语言推理底层内存系统(对吗?)所以一般来说(独立于编程语言)我们是否仍然需要内存单线程程序的模型?

谢谢!

内存模型不适用于单线程代码的原因是在 ST 代码中,一条语句接一条语句执行,不存在混淆的可能性。在多线程代码中,对象的值可能会在没有警告当前线程的情况下发生更改。内存模型概念可让您确保特定语句在所有其他线程完成更新值后执行,或者特定语句在任何其他线程读取对象值之前执行。

引用自https://en.wikipedia.org/wiki/Memory_model_(programming)

A memory model allows a compiler to perform many important optimizations. Compiler optimizations like loop fusion move statements in the program, which can influence the order of read and write operations of potentially shared variables. Changes in the ordering of reads and writes can cause race conditions.

编译器可以改变变量的读写顺序,仍然保证代码片段运行就好像read/writes是顺序完成的。但是,如果涉及多线程,这可能会导致问题,因为 reading/writing 个变量,而不是代码顺序,可能会导致与多线程相关的问题。

检查以下由 2 个线程执行的代码,它们都使用相同的变量 init 和 value:

static int init = 0;
static int value = 0;

thread_a:
while( !init )
    Sleep( 100 );
    if ( value == 100 )
        do something ...

thread_b:
    value = 100;
    init = 1;

编译器可能 运行 thread_b 的代码以不同的顺序(或并行)导致在值设置为 100 之前将 init 设置为 1。在使用单线程时,这没有意义,但是,当有多个线程检查此变量时,这可能会导致问题。而这里内存模型来解决这个问题。

一般所说的内存模型是指不同执行线程访问对象的交互。从这个意义上说,它完全与并发相关。这与内存无关。

还有另一个重要方面被称为 对象模型 并且 Stan Lippman’s book 是一个很好的学习资源(它有点过时但大部分保持不变相关的)。对象模型也没有真正讨论如何访问内存。

最接近一般情况下如何访问内存的描述是 Ulrich Drepper 的 What Every Programmer Should Know About Memory_。这篇文章是关于内存的一般观点,独立于编程语言。当然,根据对象模型的不同,不同的编程语言可能会隐藏与内存的直接交互。

I understand that a memory model is an abstraction that allows the programmer to reason about the underlying memory system using a programming language (correct?)

内存一致性模型是一组规则,允许程序员从访问状态的每个单独代理(核心)的角度推断程序在执行期间的任何时间点的可能状态, 如果满足某些条件(例如没有数据竞争)。

I wanted to know about C/C++ memory model but I found in all of the articles, blogs, youtube videos that "Memory models are only needed for concurrency"..

Can anyone please clarify to me why is this the case?

有一些规则可以被视为内存模型的一部分,这些规则也适用于单线程程序的上下文。特别是:

  • 写入同一位置后的读取将读取写入的值,而不是旧值。
  • 对同一位置的另一次写入之后的写入将覆盖先前写入的值。
  • 读取后对同一位置的写入只会在读取完成后修改该位置。

但是,这些规则被认为是如此基础和直观,以至于不值得在每个内存模型中都说明它们。对于 VLIW 架构,编译器会自动遵循这些规则。在传统架构的情况下,编译器(根据源代码中语句的顺序)和处理器都遵循这些规则(根据指令流的顺序)。所以基本上陈述它们是多余的。除此之外,单线程程序没有其他有用的规则。