Question

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

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

Was it helpful?

Solution

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.

OTHER TIPS

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.

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!

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

?

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

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.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top