A: 

They may not be in different in your current environment, but subtle changes could affect the behavior.

  • Different hardware (more processors, different memory architecture)
  • A new version of the compiler with better optimization.
  • Random variation in timing between threads. A problem may only occur one time in 10 million.
  • Different compiler optimization settings.

It is much safer in the long run to use proper multithreading constructs from the beginning, even if things seem to work for now without them.

Of course, if your program is not multi-threaded then it doesn't matter.

Darron
'volatile' in C has nothing to do with multihreading. It just prevents compiler from optimizing it out (eg register mapped to some IO stuff). But it DOES NOT insert memory fences like volatile in Java.
Piotr Lesnicki
+7  A: 

The "volatile" keyword suggests the compiler not to do certain optimizations on code involving that variable; if you just use a global variable, nothing prevents the compiler to wrongly optimize your code.

Example:

#define MYPORT 0xDEADB33F

volatile char *portptr = (char*)MYPORT;
*portptr = 'A';
*portptr = 'B';

Without "volatile", the first write may be optimized out.

friol
A: 

The volatile keyword tells the compiler to make sure that variable will never be cached. All accesses to it must be made in a consistent way as to have a consistent value between all threads. If the value of the variable is to be changed by another thread while you have a loop checking for change, you want the variable to be volatile as there is no guarantee that a regular variable value won't be cached at some point and the loop will just assume it stays the same.

Volatile variable on Wikipedia

Krunch
Cached is not the right word here, the compiler has no control over how the CPU cache handles things. What you're thinking of is keep the value in a egister rather than reading it from memory. That's correct, but I wouldn't call it caching. Thats confusing.
SoapBox
Wait wait, see my comment on Darron's anser: Volatile is NOT for multithreading!
Piotr Lesnicki
+5  A: 

They are different things. I'm not an expert in volatile semantics. But i think it makes sense what is described here.

Global

Global just means the identifier in question is declared at file-scope. There are different scopes, called function (where goto-labels are defined in), file (where globals reside), block (where normal local variables reside), and function prototype (where function parameters reside). This concept just exist to structure the visibility of identifiers. It doesn't have anything to do with optimizations.

Static

static is a storage duration (we won't look at that here) and a way to give a name declared within file scope internal linkage. This can be done for functions or objects only required within one translation unit. A typical example might be a help function printing out the accepted parameters, and which is only called from the main function defined in the same .c file.

6.2.2/2 in a C99 draft:

If the declaration of a file scope identifier for an object or a function contains the storage class specifier static, the identifier has internal linkage.

Internal linkage means that the identifier is not visible outside the current translation unit (like the help function of above).

Volatile

Volatile is a different thing: (6.7.3/6)

An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects. Therefore any expression referring to such an object shall be evaluated strictly according to the rules of the abstract machine, as described in 5.1.2.3. Furthermore, at every sequence point the value last stored in the object shall agree with that prescribed by the abstract machine, except as modified by the unknown factors mentioned previously.

The Standard provides an excellent example for an example where volatile would be redundant (5.1.2.3/8):

An implementation might define a one-to-one correspondence between abstract and actual semantics: at every sequence point, the values of the actual objects would agree with those specified by the abstract semantics. The keyword volatile would then be redundant.

Sequence points are points where the effect of side effects concerning the abstract machine are completed (i.e external conditions like memory cell values are not included). Between the right and the left of && and ||, after ; and returning from a function call are sequence points for example.

The abstract semantics is what the compiler can deduce from seeing only the sequence of code within a particular program. Effects of optimizations are irrelevant here. actual semantics include the effect of side effects done by writing to objects (for example, changing of memory cells). Qualifying an object as volatile means one always gets the value of an object straight from memory ("as modified by the unknown factors"). The Standard doesn't mention threads anywhere, and if you must rely on the order of changes, or on atomicity of operations, you should use platform dependent ways to ensure that.

For an easy to understand overview, intel has a great article about it here.

What should i do now?

Keep declaring your file-scope (global) data as volatile. Global data in itself does not mean the variables' value will equal to the value stored in memory. And static does only make your objects local to the current translation unit (the current .c files and all other files #include'ed by it).

Johannes Schaub - litb
A: 

I +1 friol's answer. I would like to add some precisions as there seem to be a lot of confusions in different answers: C's volatile is not Java's volatile.

So first, compilers can do a lot of optimizations on based on the data flow of your program, volatile in C prevents that, it makes sure you really load/store to the location every time (instead of using registers of wiping it out e.g.). It is useful when you have a memory mapped IO port, as friol's pointed out.

Volatile in C has NOTHING to do with hardware caches or multithreading. It does not insert memory fences, and you have absolutely no garanty on the order of operations if two threads do accesses to it. Java's volatile keyword does exactly that though: inserting memory fences where needed.

Piotr Lesnicki
+9  A: 

First let me mention that a static global variable, is the same as a global variable, except that you are limiting the variable to the scope of the file. I.e. you can't use this global variable in other files via the extern keyword.

So you can reduce your question to global varaibles vs volatile variables.

Now onto volatile:

Like 'const', 'volatile' is a type modifier.

The volatile keyword was created to prevent compiler optimizations that may make code incorrect, specifically when there are asynchronous events.

Objects declared as volatile may not be used in certain optimizations.

The system always reads the current true value of a volatile object at the point it is used, even if a previous instruction asked for a value from the same object. Also, the value of the object is written immediately on assignment. That means there is no caching of a volatile variable into a CPU register.

Dr. Jobb's has a great article on volatile.

Here is an example from the Dr. Jobb's article:

class Gadget
{
public:
    void Wait()
    {
        while (!flag_)
        {
            Sleep(1000); // sleeps for 1000 milliseconds
        }
    }
    void Wakeup()
    {
        flag_ = true;
    }
    ...
private:
    bool flag_;
};

If the compiler sees that Sleep is an external call, it will assume that Sleep cannot possibly change the variable flag_'s value. So the compiler may store the value of flag_ in a register. And in that case, it will never change. But if another thread calls wakeup, the first thread is still reading from the CPU's register. Wait() will never wake-up.

So why not just never cache variables into registers and avoid the problem completely? It turns out that this optimization can really save you a lot of time overall. So C/C++ allows you to explicitly disable it via the volatile keyword.

The fact above that flag_ was a member variable, and not a global variable (nor static global) does not matter. The explanation after the example gives the correct reasoning even if you're dealing with global variables (and static global variables).

A common misconception is that declaring a variable volatile is not sufficient to ensure thread safety. Operations on the variable are still not atomic, even though they are not "cached" in registers

volatile with pointers:

Volatile with pointers, works like const with pointers.

A variable of type volatile int * means that the variable that the pointer points to is volatile.

A variable of type int * volatile means that the pointer itself is volatile.

Brian R. Bondy
Nice answer. Only thing I'd add (because it's a common misconception) is that declaring a variable volatile is not sufficient to ensure thread safety. Operations on the variable are still not atomic, even though they are not "cached" in registers
jalf
Thanks for the input I added it to my answer.
Brian R. Bondy
+1 for mentioning the misconception, even though the current wording actually says the wrong thing (the "not" should be removed).
Niklas