C++03中并发的内存模型是什么?
(而且,C++11 是否更改了内存模型以更好地支持并发?)
C++ 内存模型是针对 C++ 代码读取/写入物理内存的时间和原因的规范。
在下一个 C++ 标准之前,C++ 内存模型与 C 相同。在 C++0x 标准中,预计将包含一个适合多线程的内存模型(参见此处),并且可能会成为下一个修订版的一部分C标准,C1X。当前的一个是基本的:
因此,当前状态是:仅当您有 1 个进程、其主线程且不编写取决于变量读/写的特定顺序的代码时才指定 C++ 内存操作,仅此而已。从本质上讲,这意味着除了传统的 hello world 程序之外,您还搞砸了。
当然,您会被提示添加“它今天在我的机器上运行,您不可能是对的”。正确的句子是“它今天可以在我的机器上运行,它具有硬件、操作系统(线程库)和编译器的这种特定组合,这些硬件、操作系统(线程库)和编译器彼此了解足够多,可以实现一些有点工作但可能会在某个时候中断的东西”。
好吧好吧,这有点苛刻,但地狱,甚至 Herb Sutter 也承认(只需阅读介绍),他正在谈论最普遍的 C/C++ 工具链之一的所有 2007 年之前的版本......
C++ 标准委员会试图提出一些可以解决所有这些问题的方法,同时仍然比 Java 的内存模型限制更少(因此性能更好)。
Hans Boehm 在这里收集了一些关于这个问题的论文,包括学术论文和 C++ 委员会的论文。
看到其他一些答案,似乎许多 C++ 程序员甚至都不知道您所询问的“内存模型”是什么意思。
从某种意义上说,问题是关于内存模型的:关于写入/读取重新排序(可能发生在编译器端或运行时端)有什么保证(如果有的话)?这个问题对于多线程编程非常重要,因为如果没有这样的规则,编写正确的多线程程序是不可能的,而且有些令人惊讶的事实是,由于当前缺乏显式内存模型,许多多线程程序或多或少地“靠运气”工作——通常要归功于编译器在函数调用之间假设指针别名。- 见线程不能作为库实现
在当前的 C++ 中,没有标准的内存模型。一些编译器为 volatile 变量定义内存模型,但这是非标准的。C++0x 为此目的定义了新的“原子”原语。检查最近状态的详尽起点可以在C++ 的线程和内存模型中找到
重要的链接还有并发内存模型、原子类型和C++ 数据依赖排序:原子和内存模型标准提案。
不幸的是,在 C++ 中没有像 Java 那样的“标准内存模型”。实际的实现由编译器、运行时库和处理器决定。
因此,C++ 内存模型 == 模型的混沌混搭,这意味着您总是必须尝试编写不依赖于特定内存模型的安全代码,这也适用于线程编程,因为编译器可以做到它想要在关键部分之外进行的任何优化,甚至是乱序处理!
如果您想更深入地了解共享内存一致性模型,我建议您参考以下教程。
简短的回答:没有
长答案:C++ 没有托管内存,您必须自己分配和释放它。智能指针类可以减轻这种负担。如果您忘记释放分配的内存,那就是内存泄漏和错误。如果您在释放内存后尝试使用内存,或者您尝试多次释放内存,这些也是令人讨厌的错误。
至于低级细节,C++ 没有具体说明——这取决于硬件。内存是通过指针访问的,其中包含某种内存地址。内存地址可以是物理地址或虚拟地址。如果您正在使用操作系统内核,或者您正在阅读以实模式运行的旧 DOS 代码,您只会看到物理地址。有关更多详细信息,请阅读虚拟内存,那里有很多好的资源。
x86 架构还允许使用段描述符来寻址内存。这是一大堆蠕虫,自 Win16 时代以来就没有真正使用过,如果幸运的话,你永远不必处理它。
简而言之,C++ 内存模型包括...
向下增长的堆栈——也就是说,当您压入堆栈帧时,堆栈指针的值小于原来的值
向上增长的堆,即新分配的内存的结束地址比之前的内存大。您使用 malloc() 或 new 在堆中分配内存。如果堆中没有足够的可用内存,则 malloc(或 new)调用系统函数 brk() sbrk() 以增加堆的大小。如果对 brk() 或 sbrk() 的调用失败,则 malloc 或 new 失败并出现内存不足异常。
您永远不需要关心堆栈或堆是向下还是向上增长,并且在某些系统中,它们可能以相反的方式运行。只需考虑堆栈和堆从地址空间的末端向内增长。
内存分配器 malloc,它以 8 位字节分配内存。New 也分配内存,但它分配的内存量取决于正在更新的对象的大小。
包含可执行代码的文本空间。文本位于堆下方。您不能在执行期间更改文本空间
程序可能在文本下方有其他特殊用途的部分。
您可以在 linux 系统上使用 objdump 查看程序是如何静态组织的(在加载之前)。
我注意到虽然您在问题中没有提到它,但“并发”是您分配给这个问题的关键字之一。线程系统在堆上为每个线程分配额外的线程空间,然后管理堆栈指针以在线程之间切换。
还有更多细节,其中许多是特定于特定硬件、操作系统或线程系统的,但这是基本思想。