什么是用于并发的c++ 03内存模型?

时间:2021-04-08 06:59:51

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

c++ 03中用于并发的内存模型是什么?

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

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

7 个解决方案

#1


34  

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

c++内存模型是关于读取/写入c++代码的时间和原因的规范。

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:

直到下一个c++标准,c++的内存模型与C的C++0x标准是一样的,一个适合多线程的合适的内存模型将被包含在其中(参见这里),它将成为C标准C1X的下一个修订的一部分。目前的是基本的:

  • 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.

所以,当前的状态是:只有当您有一个进程时才指定c++内存操作,它有它的主线程,并且不编写依赖于变量读/写的特定顺序的代码,仅此而已。从本质上讲,这意味着除了传统的hello world程序之外,您还会有麻烦。

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...

好吧,好吧,这有点刺耳,但即使是赫伯·萨特也承认(只要读一下介绍),他正在谈论的是2007年以前的所有版本,其中一个最普遍的C/ c++工具链……

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.

c++标准委员会试图提出一些能够解决所有这些问题的东西,但与Java的内存模型相比,仍然没有那么大的限制(因此性能更好)。

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

Hans Boehm在这里收集了一些关于这个问题的论文,包括学术论文和c++委员会的论文。

#2


23  

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

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

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++

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

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

重要的链接还包括并发内存模型、原子类型和c++数据依赖排序:原子模型和内存模型标准建议。

#3


2  

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.

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

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!

因此,c++内存模型= =混乱mix-mash模型,这意味着你总是试着编写安全代码不依赖于一个特定的内存模型,以及适用于线程编程,因为编译器可以做任何优化它希望之外的一个重要部分,甚至订单处理!

#4


2  

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

看看c++标准委员会网站上的论文:

?

吗?

#5


1  

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

http://rsim.cs.uiuc.edu/ sadve /出版/ computer96.pdf

#6


-1  

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.

答案很长:c++没有托管内存,您必须自己分配它并释放它。智能指针类可以减轻这种负担。如果忘记释放所分配的内存,那就是内存泄漏和bug。如果您尝试在释放内存后使用内存,或者尝试多次释放内存,这些都是非常讨厌的bug。

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.

至于底层的细节,c++没有指定——这取决于硬件。通过指针访问内存,指针包含某种内存地址。内存地址可以是物理地址,也可以是虚拟地址。只有当您在操作系统内核上工作时,或者当您正在阅读在真实模式下运行的旧DOS代码时,才会看到物理地址。要了解更多细节,请阅读虚拟内存,那里有很多很好的资源。

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.

x86体系结构还允许使用段描述符来寻址内存。这是一大堆蠕虫,从Win16时代开始就没有真正被使用过,如果你幸运的话,你永远都不用处理它。

#7


-8  

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

简而言之,c++内存模型由……

  • 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.

    向上增长的堆(即新分配内存的最终地址)比内存之前的堆要大。使用malloc()或new在堆中分配内存。如果堆中没有足够的可用内存,那么malloc(或new)调用系统函数brk() sbrk()来增加堆的大小。如果对brk()或sbrk()的调用失败,那么malloc或new失败的内存异常。

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.

    一种内存分配器,malloc,它以8位字节分配内存。New也分配内存,但是它分配的内存数量是基于被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.

您可以看到如何在linux系统上使用objdump静态地(在加载之前)组织程序。

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.

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

#1


34  

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

c++内存模型是关于读取/写入c++代码的时间和原因的规范。

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:

直到下一个c++标准,c++的内存模型与C的C++0x标准是一样的,一个适合多线程的合适的内存模型将被包含在其中(参见这里),它将成为C标准C1X的下一个修订的一部分。目前的是基本的:

  • 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.

所以,当前的状态是:只有当您有一个进程时才指定c++内存操作,它有它的主线程,并且不编写依赖于变量读/写的特定顺序的代码,仅此而已。从本质上讲,这意味着除了传统的hello world程序之外,您还会有麻烦。

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...

好吧,好吧,这有点刺耳,但即使是赫伯·萨特也承认(只要读一下介绍),他正在谈论的是2007年以前的所有版本,其中一个最普遍的C/ c++工具链……

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.

c++标准委员会试图提出一些能够解决所有这些问题的东西,但与Java的内存模型相比,仍然没有那么大的限制(因此性能更好)。

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

Hans Boehm在这里收集了一些关于这个问题的论文,包括学术论文和c++委员会的论文。

#2


23  

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

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

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++

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

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

重要的链接还包括并发内存模型、原子类型和c++数据依赖排序:原子模型和内存模型标准建议。

#3


2  

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.

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

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!

因此,c++内存模型= =混乱mix-mash模型,这意味着你总是试着编写安全代码不依赖于一个特定的内存模型,以及适用于线程编程,因为编译器可以做任何优化它希望之外的一个重要部分,甚至订单处理!

#4


2  

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

看看c++标准委员会网站上的论文:

?

吗?

#5


1  

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

http://rsim.cs.uiuc.edu/ sadve /出版/ computer96.pdf

#6


-1  

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.

答案很长:c++没有托管内存,您必须自己分配它并释放它。智能指针类可以减轻这种负担。如果忘记释放所分配的内存,那就是内存泄漏和bug。如果您尝试在释放内存后使用内存,或者尝试多次释放内存,这些都是非常讨厌的bug。

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.

至于底层的细节,c++没有指定——这取决于硬件。通过指针访问内存,指针包含某种内存地址。内存地址可以是物理地址,也可以是虚拟地址。只有当您在操作系统内核上工作时,或者当您正在阅读在真实模式下运行的旧DOS代码时,才会看到物理地址。要了解更多细节,请阅读虚拟内存,那里有很多很好的资源。

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.

x86体系结构还允许使用段描述符来寻址内存。这是一大堆蠕虫,从Win16时代开始就没有真正被使用过,如果你幸运的话,你永远都不用处理它。

#7


-8  

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

简而言之,c++内存模型由……

  • 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.

    向上增长的堆(即新分配内存的最终地址)比内存之前的堆要大。使用malloc()或new在堆中分配内存。如果堆中没有足够的可用内存,那么malloc(或new)调用系统函数brk() sbrk()来增加堆的大小。如果对brk()或sbrk()的调用失败,那么malloc或new失败的内存异常。

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.

    一种内存分配器,malloc,它以8位字节分配内存。New也分配内存,但是它分配的内存数量是基于被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.

您可以看到如何在linux系统上使用objdump静态地(在加载之前)组织程序。

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.

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