Volatile in C ++ 11

In C ++ 11, the machine model has changed from a single thread to a multi-threaded machine.

Does this mean that a typical example of optimized reading is static int x; void func() { x = 0; while (x == 0) {} } static int x; void func() { x = 0; while (x == 0) {} } static int x; void func() { x = 0; while (x == 0) {} } will no longer be in C ++ 11?

EDIT: for those who don't know this example (I'm seriously surprised), please read the following: https://en.wikipedia.org/wiki/Volatile_variable

EDIT2: Well, I really expected everyone who knew volatile to see this example.

If you use the code in the example, the variable read in the loop will be optimized, making the loop infinite.

Of course, the solution is to use volatile , which will force the compiler to read the variable on every access.

My question is that this is an obsolete problem in C ++ 11, since the machine model is multi-threaded, so the compiler must consider the simultaneous access to the variable that must be present in the system.

+24
c ++ volatile c ++ 11
Oct 14
source share
2 answers

Whether it is optimized depends entirely on compilers and what they prefer to optimize. The C ++ 98/03 memory model does not recognize the possibility of changing x between setting it and retrieving the value.

The C ++ 11 memory model recognizes that x can be changed. However, this does not bother. Non-atomic access to variables (i.e., not using std::atomic or the corresponding mutexes) gives undefined behavior. Therefore, for the C ++ 11 compiler, it is fine to assume that x never changes between writing and reading, since undefined behavior may mean: "a function never sees x changes ever."

Now let's see what C ++ 11 says about volatile int x; . If you put this there, and you have another thread mess with x , you still have undefined behavior. Volatile does not affect thread behavior. The C ++ 11 memory model does not define reading or writing from / to x to atomic, and does not require the memory barriers necessary for non-atomic reading / writing to be properly ordered. volatile has nothing to do with this anyway.

Oh, your code may work. But C ++ 11 does not guarantee this.

What volatile tells the compiler is that it cannot optimize memory reading from this variable. However, processor cores have different caches, and most memory operations do not immediately go to main memory. They are stored in this main local cache and can be written ... after all.

Processors have ways to force cache lines into memory and synchronize memory access between different cores. These memory barriers allow two threads to communicate effectively. Mere reading from memory in one core written in another core is not enough; the kernel that wrote the memory had to create a barrier, and the kernel that had to read it had to fill this barrier before reading it to get the data.

volatile does not guarantee this. Volatile works with "hardware, mapped memory, etc.", because the hardware that writes this memory ensures that the cache problem is resolved. If after each write the CPU cores give out a memory barrier, you can basically kiss any hope of farewell. Therefore, C ++ 11 has a specific language that says that constructs are required to create a barrier.

volatile - this is access to memory (when to read); threading is the integrity of the memory (what is actually stored there).

The C ++ 11 memory model is specific with respect to which operations will make records in one thread become visible in another. This is about the integrity of memory that is not processed by volatile . And memory integrity usually requires both threads to do something.

For example, if thread A locks the mutex, writes and then unlocks it, the C ++ 11 memory model requires the write to become visible to thread B if thread B later locks it. Until he actually acquires this particular castle, undefined what value is. This material is detailed in section 1.10 of the standard.

See the code you are quoting for the standard. Section 1.10, p8, discusses the ability of some library calls to cause a thread to “synchronize” with another thread. Most of the other paragraphs explain how synchronization (and other things) creates the order of operations between threads. Of course, your code does not call any of this. There is no synchronization point, no ordering of dependencies, nothing.

Without such protection, without any synchronization or order, 1.10 p21 comes in:

A program execution contains a data race if it contains two conflicting actions in different threads, at least one of which is not atomic, and does not occur before the other. Any such data race results in undefined behavior.

Your program contains two conflicting actions (reading from x and writing to x ). None of them are atomic, and not one of them is ordered by synchronization in front of the other.

Thus, you have reached undefined behavior.

Thus, the only case where you get guaranteed multi-threaded behavior of the C ++ 11 memory model is to use the correct mutex or std::atomic<int> x with the corresponding atomic load / storage calls.

Oh, and you don't need to do x volatile either. Each time you call a (non-built-in) function, this function or something that it calls can change the global variable. Therefore, it cannot optimize the reading of x in a while . And each C ++ 11 mechanism for synchronization requires a function call. This happens to cause a memory barrier.

+69
Oct 14 '12 at 1:17
source share

The Intel Developers section says: “Volatility: Almost useless for multi-threaded programming.”

In this example, the signal handler from cppreference.com uses the volatile keyword .

 #include <csignal> #include <iostream> namespace { volatile std::sig_atomic_t gSignalStatus; } void signal_handler(int signal) { gSignalStatus = signal; } int main() { // Install a signal handler std::signal(SIGINT, signal_handler); std::cout << "SignalValue: " << gSignalStatus << '\n'; std::cout << "Sending signal " << SIGINT << '\n'; std::raise(SIGINT); std::cout << "SignalValue: " << gSignalStatus << '\n'; } 
+1
Aug 15 '18 at 18:30
source share



All Articles