Intel® Moderncode for Parallel Architectures
Support for developing parallel programming applications on Intel® Architecture.
1696 Discussions

Use of Volatile on Single/Multi Processor application

Speigel
Beginner
1,194 Views
Ihavereadmany arguementswhere some people findC++ volatile keyworduseful and some don't. But, still I have somedoubts which I want to clarify.
I agree that its not useful in a multi-threadedapplication where thevarious synchronization objects provided memory fenceanyways to the critical section.Is it true?

Are there any scenarioson anyCPU architectures where volatile keywordcan beof any use?

How is declaring a variable volatiledifferent ifthe variableis a primitive type or a class object?And What ifthe volatile class object is shared between two threadsusing synchronization objects when running on the same/differentprocessor? Please be detailed. Thanks.
0 Kudos
7 Replies
Michael_K_Intel2
Employee
1,194 Views
Hi,

the volatile modifier indicates to the compiler that variables might change their value in main memory. This indicates to the compiler that this variable must be re-loaded from the main memory at any usage.

Volatile variables occur in multi-threaded programs, where they indicate that another thread might have changed the value of a variable in main memory. For example, the following spin loop does not work correctly without making flag volatile:

while(!flag) {}

A compiler might assign the non-volatile flag to a register, not re-loading it in every iteration of the spin loop.

Without multithreadin, volatile variables are still useful. For example, a volatile variable might be assigned to a memory location that might be changed by a hardware device or RDMA. In this case, the modification also occurs outside of the current instruction stream and might not be recognized if the compiler moves the variable into a register.

Does that answer your question?

Cheers,
-michael
0 Kudos
Speigel
Beginner
1,194 Views
Thanks Michael,

So in the case where two threads are running on the same CPU,is it not useless to declare 'flag' as volatile becausethe variable is of integral type and can beexecuted atomically. Ona single CPU, atomic instructions are not interrupted and thereforethread A will immediately notice the change in the value of the flag as soon as thread B changes it. Therefore declaring flag as volatile doesn't seem usefulon the single CPU multi-threaded application. Doesthis sounds right?

Inthe case where the threads are running on multiple CPU, would any change by the thread A to 'flag' will invalidate/update the cache lineaccross all the processors?Or is it true for only Dual Core processors?

In your example where the variable is modified bya hardware device or RDMA, why wouldn't the changebe noticed in the application?
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,194 Views
>>Therefore declaring flag as volatile doesn't seem usefulon the single CPU multi-threaded application. Doesthis sounds right?

No this is not the case.

bool done = false;

void waitTillDone()
{
while(!done)
_mm_pause();
}

When done is not volatile, the compiler will generate something like the following

mov eax, done ; fetch current value of done
loop:
test eax, eax ; test registered copy of done for 0
je loop ; retest (registered copy of done)

If the waitTillDone were called when done==false then the code executing in one thread will never see the subsequent change of done made by another thread.

With

volatile bool done = false;

the compiler will generate something like the following

loop:
mov eax, done
test eax, eax
je loop

volatile is required when something outside the current compile time context might change the value of a variable that might get registerized.

Note, in Debug mode (with no optimizations) the compiler may generate code that re-fetches the value from memory (as opposed to keeping value in register). This produces a situation where the Debug version of the code works while the Release version fails.

Often you will have functions of code that use a shared variable only once. In these cases the code will work without volatile. However, should the program be compiled with interprocedural optimizations, a function that was out of line may get inlined. In this case, and depending on what else got inlined, the shared variable may be already present in one of the registers. And in which case your code may break.

Note, volatile is not the same as an atomic operation.

Jim Dempsey


0 Kudos
Speigel
Beginner
1,194 Views
Yeah, I got that. Thanks.

But declaring volatile doesn't gaurantee that the procesor wouldn't try to optimize the code and in which case the code may look like

mov eax, done

loop:
test eax, eax
je loop

How does it work in this case?

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,194 Views
while(!done)
continue;

volatile on done guarantees* that the memory location(s) of done is read on each iteration.

*assuming no bug in compiler

volatile is not the same as atomic (even for read of object). It only guarantees that the compiler will extract or store an object from/to memory at that point in the source code.

From MSDN:

Objects declared as volatile are not used in certain optimizations because their values can change at any time. The system always reads the current value of a volatile object at the point it is requested, even if a previous instruction asked for a value from the same object. Also, the value of the object is written immediately on assignment.

Also, when optimizing, the compiler must maintain ordering among references to volatile objects as well as references to other global objects. In particular,

A write to a volatile object (volatile write) has Release semantics; a reference to a global or static object that occurs before a write to a volatile object in the instruction sequence will occur before that volatile write in the compiled binary.

A read of a volatile object (volatile read) has Acquire semantics; a reference to a global or static object that occurs after a read of volatile memory in the instruction sequence will occur after that volatile read in the compiled binary.

This allows volatile objects to be used for memory locks and releases in multithreaded applications.

Jim

0 Kudos
Speigel
Beginner
1,194 Views
Thank you all for your comments.

I had another question in my very first comments which is below.

1) How is declaring a variable volatile different if the variable is a primitive type or a class object? I am guessing, declaring a class object volatile will make all of its members volatile. If this is true, then is this rule strictly followed by the compilers?

2)Is there a need to declare a variable (integral or class object)volatile whenaccess to it isprotected bysynchronization objectsin multi-threaded environment?
0 Kudos
Dmitry_Vyukov
Valued Contributor I
1,194 Views
Quoting Speigel
Thank you all for your comments.

I had another question in my very first comments which is below.

1) How is declaring a variable volatile different if the variable is a primitive type or a class object? I am guessing, declaring a class object volatile will make all of its members volatile. If this is true, then is this rule strictly followed by the compilers?

2)Is there a need to declare a variable (integral or class object)volatile whenaccess to it isprotected bysynchronization objectsin multi-threaded environment?

> How is declaring a variable volatile different if the variable is a primitive type or a class object? I am guessing, declaring a class object volatile will make all of its members volatile

Yes.

> If this is true, then is this rule strictly followed by the compilers?

Can't say for all C/C++ compilers out there, but ISO C/C++ compliant compilers should.

> Is there a need to declare a variable (integral or class object)volatile whenaccess to it isprotected bysynchronization objectsin multi-threaded environment?

No. Synchronization object takes care of synchronization, that's why it is called synchronization object.


0 Kudos
Reply