C++03 中并发的内存模型是什么?

(而且,C++11是否改变了内存模型以更好地支持并发?)

有帮助吗?

解决方案

C++ 内存模型是关于 C++ 代码何时以及为何读取/写入物理内存的规范。

在下一个 C++ 标准之前,C++ 内存模型与 C 相同。在 C++0x 标准中,预计将包含用于多线程的正确内存模型(请参阅 这里),并且它可能会成为 C 标准下一个修订版 C1X 的一部分。目前的情况是初级的:

  • 它仅指定当前程序可观察到的内存操作的行为。
  • 当多个进程访问同一内存时,它没有说明并发内存访问(没有共享内存或进程的概念)。
  • 当多个线程访问同一内存时,它没有说明并发内存访问(没有线程的概念)。
  • 它无法指定内存访问的顺序(编译器优化包括代码移动和最近的处理器重新排序访问,两者都可能破坏诸如双重检查初始化之类的模式)。

所以,目前的状态是:仅当您有 1 个进程及其主线程并且不编写依赖于变量读/写的特定顺序的代码时才指定 C++ 内存操作,仅此而已。从本质上讲,这意味着除了传统的 hello world 程序之外,你已经完蛋了。

当然,系统会提示您添加该内容 “它今天在我的机器上运行,你不可能是对的”. 。正确的句子是 “它今天在我的机器上运行,具有硬件、操作系统(线程库)和编译器的特定组合,这些组合彼此足够了解,可以实现一些在某种程度上有效但可能会在某个时候崩溃的东西”.

好吧好吧,这有点苛刻,但见鬼, 甚至赫伯·萨特也承认 (只需阅读简介)他正在谈论最普遍的 C/C++ 工具链之一的所有 2007 年之前的版本...

C++ 标准委员会试图提出一种解决所有这些问题的方法,同时仍然比 Java 的内存模型限制更少(因此性能更好)。

汉斯·伯姆收集了 这里 一些有关该问题的论文的指示,包括学术论文和 C++ 委员会的论文。

其他提示

看到其他一些答案,似乎很多C ++程序员甚至都不知道“内存模型”是什么。你问的是手段。

问题是关于内存模型的意义:什么保证(如果有的话)有关于写/读重新排序(可能发生在编译器端或运行时端)?这个问题对于多线程编程非常重要,因为没有这样的规则编写正确的多线程程序是不可能的,并且有些令人惊讶的事实是当前缺乏显式存储器模型许多多线程程序或多或少地“纯粹运气”工作。 - 最常见的是编译器在函数调用中假设指针别名。 - 请参阅线程无法实现为图书馆

在当前的C ++中,没有标准的内存模型。有些编译器为volatile变量定义了内存模型,但这是非标准的。 C ++ 0x定义了新的“原子”为此目的的原始。可以在线程和内存模型中找到检查最近状态的详尽起点for C ++

重要链接也是并发内存模型原子类型 C ++数据依赖性排序:原子与内存模型标准提案。

不幸的是,在C ++中没有“标准内存模型”。像Java那样。实际的实现由编译器,运行时库和处理器决定。

因此C ++内存模型==混沌混合模型,这意味着你总是必须尝试编写不依赖于特定内存模型的安全代码,这也适用于线程编程,因为编译器可以在关键部分之外进行任何想要的优化,甚至是乱序处理!

看看C++标准委员会网站上的论文怎么样:

?

如果您想更深入地了解共享内存一致性模型,我将向您推荐以下教程。

http://rsim.cs.uiuc.edu/~sadve /Publications/computer96.pdf

简短回答:没有

答案很长:C ++没有托管内存,你必须自己分配并释放它。智能指针类可以减轻这种负担。如果你忘记释放你分配的内存,那就是内存泄漏和bug。如果你在释放后尝试使用内存,或者你尝试不止一次释放内存,那些也是令人讨厌的错误。

至于低级细节,C ++没有指定 - 这取决于硬件。通过指针访问内存,指针包含某种内存地址。内存地址可以是物理地址或虚拟地址。如果您正在使用操作系统内核,或者您正在读取以实模式运行的旧DOS代码,则只会看到物理地址。有关详细信息,请阅读虚拟内存,这里有很多好的资源。

x86架构还允许使用段描述符来寻址内存。这是一整套蠕虫,自Win16以来就没有真正使用过,如果你很幸运,你将永远不必处理它。

简而言之,C++ 内存模型包括...

  • 向下增长的堆栈 - 也就是说,当您压入堆栈帧时,堆栈指针的值小于原来的值

  • 向上增长的堆,即新分配的内存的结束地址比之前的内存更大。您可以使用 malloc() 或 new 在堆中分配内存。如果堆中没有足够的可用内存,则 malloc(或 new)调用系统函数 brk() sbrk() 来增加堆的大小。如果对 brk() 或 sbrk() 的调用失败,则 malloc 或 new 会失败并出现内存不足异常。

您永远不需要关心堆栈或堆是向下还是向上增长,并且在某些系统中它们可能会以相反的方式运行。只需考虑堆栈和堆从地址空间的末端向内增长。

  • 内存分配器 malloc,以 8 位字节分配内存。New 也分配内存,但它分配的内存量取决于要新建的对象的大小。

  • 包含可执行代码的文本空间。文本位于堆下方。您无法在执行期间更改文本空间

程序可能在文本下方有其他特殊用途的部分。

您可以在 Linux 系统上使用 objdump 查看程序是如何静态组织的(在加载之前)。

我注意到,虽然您在问题中没有提及,但“并发”是您分配给该问题的关键字之一。线程系统为每个线程在堆上分配额外的线程空间,然后管理堆栈指针以在线程之间切换。

还有更多细节,其中许多特定于特定硬件、操作系统或线程系统,但这是基本思想。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top