Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should ALL global variables be volatile-qualified?

In this example, does correctness require global_value to be declared volatile?

int global_value = 0;

void foo () {
    ++ global_value;
}

void bar () {
    some_function (++global_value);
    foo ();
    some_function (++global_value);
}

My understanding is that volatile is "intended" for pointers to mapped memory and variables which can be modified by signals (and emphatically not for thread-safety) but it's easy to imagine that bar might compile to something like this:

push EAX
mov EAX, global_value
inc EAX
push EAX
call some_function
call foo
inc EAX
push EAX
call some_function
mov global_value, EAX
pop EAX

This is clearly not correct, but even without volatile I believe it is valid according to the C abstract machine. Am I wrong or is it valid?

If so, it seems to me that volatile is routinely overlooked. This would be nothing new!


Extended Example

void baz (int* i) {
    some_function (++*i);
    foo ();
    some_function (++*i);
}

int main () {
    baz (&global_value);
}

Even if bar is guaranteed to compile into a correct dont-cache-global_value implementation, will baz be similarly correct, or is it allowed to cache the non-volatile value of *i?

like image 720
spraff Avatar asked Jul 28 '11 11:07

spraff


People also ask

When Should a variable be volatile?

A variable should be declared volatile whenever its value could change unexpectedly. In practice, only three types of variables could change: Memory-mapped peripheral registers. Global variables modified by an interrupt service routine.

What are two reasons why you should not use global variables?

Global variables can be altered by any part of the code, making it difficult to remember or reason about every possible use. A global variable can have no access control. It can not be limited to some parts of the program. Using global variables causes very tight coupling of code.

Why are global variables considered bad?

Non-const global variables are evil because their value can be changed by any function. Using global variables reduces the modularity and flexibility of the program. It is suggested not to use global variables in the program. Instead of using global variables, use local variables in the program.

When should I use volatile in C++?

The volatile keyword in C++11 ISO Standard code is to be used only for hardware access; do not use it for inter-thread communication. For inter-thread communication, use mechanisms such as std::atomic<T> from the C++ Standard Library.


2 Answers

No, the volatile keyword is not necessary here. Since global_value is visible outside the function bar, the compiler must not assume that it remains the same if another function is called.

[Update 2011-07-28] I found a nice citation that proves it all. It's in ISO C99, 5.1.2.3p2, which I am too lazy to copy here in its entirety. It says:

At certain specified points in the execution sequence called sequence points, all side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place.

Sequence points include:

  • The call to a function, after the arguments have been evaluated (6.5.2.2).
  • The end of a full expression: [...] the expression in an expression statement (6.8.3); [...]

There you have your proof.

like image 77
Roland Illig Avatar answered Oct 19 '22 05:10

Roland Illig


The only uses of volatile involve longjmp, signal handlers, memory-mapped device drivers, and writing your own low-level multi-threaded synchronization primitives. For this last use however, volatile is not sufficient and may not even be necessary. You'll definitely also need asm (or compiler-specific or C1x atomics) for synchronization.

volatile is not useful for any other purposes, including the code you asked about.

like image 45
R.. GitHub STOP HELPING ICE Avatar answered Oct 19 '22 03:10

R.. GitHub STOP HELPING ICE