C++ Threads

I went to a talk by Hans Boehm about threads in C++. He was mostly discussing the plans for the future C++0x standard. He said it was important to get threads right, even though they are hard to use correctly, because they would most likely be the base for any other multi-processing paradigm. That seems reasonable from a language design perspective.

C++0x will include a memory model designed to support threading. There are two main restrictions on a compiler.

The first is that speculative stores are forbidden: the compiler may not generate a store to a memory location which could be accessed in another thread unless the program unconditionally stores to that location. This permits a program to execute code which only conditionally stores to a global variable if a lock is held. Permitting a speculative store would mean that the compiler could change the variable without holding a lock. The variable would only be changed to the value it apparently already has, of course, but in a multi-threaded program the variable might have changed after the value was loaded.

The second restriction is that accesses to fields of structs which are not bitfields may not be grouped together. The intent is to permit separate locks to control different fields of a struct. The compiler is still permitted to group bitfields; otherwise it would be impossible on most processors to change a bitfield value at all. This does mean that on a processor which does not support byte stores, such as the early Alphas, or the MorphoRISC1, byte fields in a struct must be padded to the minimum store size.

The memory model will forbid moving instructions from before a critical section into the critical section. However, instructions may be moved from after the critical section into the critical section. Naturally, instructions may never move out of the critical section.

He briefly discussed the general concept of a data race. If two threads access the same variable without a lock, then in all possible execution paths there must be a single assignment which sets the value to be read. Since threads can execute in arbitrary orders, that single assignment must precede a lock acquired by both threads, or must be done before the threads start, or something like that. If there are two possible assignments before the access to the variable, the program is undefined.

C++0x will provide atomic types which are essentially always accessed via locks.

These ideas help formalize the threading model, to make clear what is permitted and what is not. But they don’t help programmers write correct code. They mainly help compiler developers coherently explain what code is permitted and what is not.


Posted

in

by

Tags:

Comments

Leave a Reply