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

发布于 2024-07-08 07:54:28 字数 64 浏览 6 评论 0 原文

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

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

What is the memory model for concurrency in C++03?

(And, does C++11 change the memory model to support concurrency better?)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

旧街凉风 2024-07-15 07:54:28

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

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

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

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

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

好吧好吧,这有点苛刻,但是地狱, 甚至 Herb Sutter 也承认(只需阅读简介),他正在谈论最普遍的 C/C++ 工具链之一的所有 2007 年之前的版本...

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

Hans Boehm 在此处收集了一些关于该问题的论文,包括学术论文和来自C++ 委员会。

The C++ memory model is the specification of when and why physical memory is read/written with respect to C++ code.

Until the next C++ standard, the C++ memory model is the same as C. In the C++0x standard, a proper memory model for multithreading is expected to be included (see here), and it will be part possibly of the next revision of the C standard, C1X. The current one is rudimentary:

  • it only specifies the behavior of memory operations observable by the current program.
  • it doesn't say anything about concurrent memory accesses when multiple processes access the same memory (there is no notion of shared memory or processes).
  • it doesn't say anything about concurrent memory accesses when multiple threads access the same memory (there is no notion of threads).
  • it offers no way to specify an ordering for memory accesses (compiler optimizations include code motion and recent processors reorder accesses, both can break patterns such as double checked initialization).

So, the current state is: C++ memory operations are only specified when you have 1 process, with its main thread and don't write code which depends on a specific ordering of variable read/writes and that's it. In essence, this means that aside from the traditional hello world program you're screwed.

Of course, you'll be prompt to add that "it works today on my machine, you can't possibly be right". The correct sentence would be "it works today on my machine with this specific combination of hardware, operating system (thread library) and compiler who know enough of each other to implement something which is somewhat working but will probably break at some point".

Ok ok, this is a bit harsh but hell, even Herb Sutter acknowledges that (just read the intro) and he is talking about all pre 2007 versions of one of the most ubiquitous C/C++ toolchain...

The C++ standard committee attempts to come up with something which will address all those issues while still being less constraining (and thus better performing) than Java's memory model.

Hans Boehm has collected here some pointers to papers on the issue, both academic, and from the C++ committee.

一梦浮鱼 2024-07-15 07:54:28

看到其他一些答案,似乎许多 C++ 程序员甚至不知道您所询问的“内存模型”意味着什么。

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

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

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

Seeing some other answers, it seems many C++ programmers are not even aware what the "memory model" you are asking about means.

The questions is about memory model in the sense: what guarantees (if any) are there about write / read reordering (which may happen on the compiler side or on the runtime side)? This question is very important for multithreaded programming, as without such rules writing correct multithread programs is not possible, and somewhat surprising truth is with current lack of explicit memory model many multithreaded programs work more or less "by sheer luck" - most often thanks to compilers assuming pointer aliasing across function calls. - see Threads Cannot be Implemented as a Library

In current C++ there is no standard memory model. Some compilers define memory model for volatile variables, but this is nonstandard. C++0x defines new "atomic" primitives for this purpose. Exhaustive starting point to check what recent status is can be found at Threads and memory model for C++

Important links are also Concurrency memory model, Atomic Types and C++ Data-Dependency Ordering: Atomics and Memory Model standard proposals.

你在看孤独的风景 2024-07-15 07:54:28

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

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

Unfortunately in C++ there is no "Standard Memory Model" like that of Java. The actual implementation is left up to the compiler, runtime libraries and processors.

Thus the C++ memory model == chaotic mix-mash of models, which means you always have to try to write safe code that doesn't depend on a specific memory model, and that goes for threaded programming as well, because the compiler can do any optimization it wants to outside of a critical section, even out of order processing!

趴在窗边数星星i 2024-07-15 07:54:28

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

What about checking the papers on the C++ standard committee website:

?

被你宠の有点坏 2024-07-15 07:54:28

如果您想更深入地了解共享内存一致性模型,我建议您参考以下教程。

http://rsim.cs.uiuc.edu/~sadve/Publications/计算机96.pdf

If you'd like to get a deeper understanding of shared memory consistency models, I'd refer you to the following tutorial.

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

一杯敬自由 2024-07-15 07:54:28

简短的回答:没有

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

至于底层细节,C++ 没有指定 - 这取决于硬件。 内存是通过指针访问的,指针包含某种内存地址。 内存地址可以是物理地址,也可以是虚拟地址。 仅当您正在处理操作系统内核或正在阅读以实模式运行的旧 DOS 代码时,您才会看到物理地址。 有关更多详细信息,请阅读虚拟内存,那里有很多好的资源。

x86 架构还允许使用段描述符对内存进行寻址。 这是另一种蠕虫病毒,自从 Win16 时代以来就没有真正被使用过,如果你幸运的话,你将永远不需要处理它。

Short answer: there is none

Long answer: C++ does not have managed memory, you have to allocate it and free it yourself. Smart pointer classes can make this less burdensome. If you forget to free memory that you allocated, that's a memory leak and a bug. If you try to use memory after freeing it, or you try to free memory more than once, those are also nasty bugs.

As for the low-level details, C++ does not specify that - it's up to the hardware. Memory is accessed through pointers, which contain some sort of memory address. Memory addresses can either be physical addresses or virtual addresses. You'll only see physical addresses if you're working on an operating system kernel, or if you're reading old DOS code that ran in real mode. For more details, read up virtual memory, there's lots of good resources out there.

The x86 architecture also allows memory to be addressed using segment descriptors. This is a whole nother can of worms, which hasn't really been used since the days of Win16, and if you're lucky, you'll never have to deal with it.

沉默的熊 2024-07-15 07:54:28

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

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

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

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

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

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

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

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

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

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

In a nutshell, the C++ memory model consists of...

  • A stack that grows downward -- that is, when you push a stack frame the stack pointer has a value less that it was

  • A heap that grows upward, that is the end address of the newly allocated memory is greater it was before the memory. You allocate memory in the heap using malloc() or new. If there is not enough memory available in the heap then malloc (or new) calls the system function brk() sbrk() to increase the size of the heap. If the call to brk() or sbrk() fails then malloc or new fails with an out of memory exception.

You should never need to care whether the stack or heap grow down or up and in some systems these may operate the other way around. Just consider that the stack and heap grow inwards from the ends of the address space.

  • A memory allocator, malloc, which allocates memory in terms of 8-bit bytes. New also allocates memory, but the amount of memory that it allocates is based on the size of the object being newed.

  • Text space which contains the executable code. Text resides below the heap. You cannot alter the text space during execution

A program may have other special purpose sections below text.

You can see how a program is organized statically (before it's loaded) using objdump on linux systems.

I noticed that although you didn't mention it in your question, "concurrency" is one of the keywords you assigned to this question. Threading systems allcoate additional thread space on the heap for each thread and then manage the stack pointer to switch between threads.

There are a lot more details, many of which are specific to particluar hardware, OSes, or threading system, but that's the essential idea.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文