36

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

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

ruakh
  • 175,680
  • 26
  • 273
  • 307
yesraaj
  • 46,370
  • 69
  • 194
  • 251
  • You should rewrite the question to be more clear – 1800 INFORMATION Oct 21 '08 at 04:50
  • 1
    I agree - the question is important, but very badly worded. I will try to improve. (Reputation Game Rant: I found it ironic this question is marked as community wiki - this means no rep for answers, no matter how deep, technical or good they may be) – Suma Oct 21 '08 at 07:36
  • I think the community wiki system is good. The problem is the person who asked this question was a newcomer and since the actual function of community wiki isn't clear to newcomers, many make it wiki because it just sounds cool. I did exactly the same thing when I started here :) – Robert Gould Oct 21 '08 at 08:00

7 Answers7

33

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.

mikelong
  • 3,694
  • 2
  • 35
  • 40
bltxd
  • 8,825
  • 5
  • 30
  • 44
  • 1
    I think you're a little harsh here. C++/C are the languages of choice for most real-time, mission-critical, multi-threaded embedded systems. While the C++ standard has no MT support, no C++ compiler vendor will get far selling a tool which cannot be used in an MT environment. – Roddy Oct 21 '08 at 07:43
  • You're right, I reread myself and this sounds harsh. However I suggest you read this if you haven't: http://www.open-std.org/JTC1/sc22/wg21/docs/papers/2007/n2197.pdf All C/C++ toolchains are affected by this issue. – bltxd Oct 21 '08 at 08:15
  • The double-checked pattern is perfectly fine according to C. Theory doesn't match practice, unfortunately, as real processors do reorder. – MSalters Oct 21 '08 at 08:36
  • Pointers ? C has no notion of threads, are you talking about single threaded behavior ? – bltxd Oct 21 '08 at 09:11
  • 3
    Sorry, but an assertion like "the double-checked pattern is fine according to C" is nonsense, for the reasons given in the post. With the memory model under development, I don't think it's fine either by default, but there should be a way to make the compiler produce the needed barriers (through so-called 'low-level atomics', IIRC). – Blaisorblade Aug 02 '10 at 12:46
  • Nonsense? The standard describes an ideal world in which it works - no reordering exists in that world, and things happen sequentially. It then acknowledges that specific non-observable transformations are allowed, and describes what (non-)observable means - a concession to reality. The amount of reordering needed to break DCLP is observable, and thus disallowed. – MSalters Aug 02 '10 at 12:59
  • 1
    It's true: "C++0x" and C1x will be the first C++ and C standards to say anything whatsoever about what happens when you use threads. Without this, really bad things do happen: see the blog entry http://www.thegibson.org/blog/archives/23 "Memory ordering and memory models" (and the linked LKML and GCC list threads) for an example of what can happen when there are no rules to tell the compiler implementors what they can and cannot do. So, sure, many things seem to work now, but that's mostly luck... – SamB Aug 20 '10 at 21:35
23

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.

Suma
  • 33,181
  • 16
  • 123
  • 191
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.

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!

Robert Gould
  • 68,773
  • 61
  • 187
  • 272
  • That is incorrect. There is no *assumed* memory model except that there is a working stack & a heap. The model is not a chaotic mix-up, it's just whatever the hardware has on it. IE, harvard or von neumann, no heap, heap. It's hardware based, which denotes an order to it. – Paul Nathan Oct 21 '08 at 04:57
  • 1
    @Vlion: you're mistaken. The memory model is a description of when and why physical memory get read/written. Hardware is mostly irrelevant here except that what will be specified must be implementable on current hardware ! – bltxd Oct 21 '08 at 06:56
  • Thanks blue.tuxedo for covering me there ;) Should have been more specific on my answer for those that aren't familiar with the term itself. – Robert Gould Oct 21 '08 at 07:55
2

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

?

Luc Hermitte
  • 31,979
  • 7
  • 69
  • 83
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

reprogrammer
  • 14,298
  • 16
  • 57
  • 93
-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.

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.

Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
-8

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.

mxg
  • 1,337
  • 1
  • 12
  • 15