Jump to content
  • Advertisement
Sign in to follow this  
fpsgamer

[C++] How to properly use the 'volatile' keyword...

This topic is 3921 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have no clue when to use the volatile keyword in my concurrent applications. I am yet to find a place where using it has had any noticeable effect on preserving atomicity. I tend to toss in that keyword when some concurrency bug occurs in hopes that that will fix it ... but I obviously don't know what I'm doing. ...Also can it be used on complex types like class/struct instances, or just basic types?

Share this post


Link to post
Share on other sites
Advertisement
The keyword "volatile" has nothing to do with atomic operations. It's just a hint to the compiler that the contents of a variable may change by outside code, for example from a different thread or by a DMA transfer. It's mainly used for spinlocks:


volatile bool isFinished = false;

void spinLock()
{
while(!isFinished)
{
}
}






Without the "volatile" keyword there may be an infinite loop because the compiler might think that the variable "isFinished" can never be changed, so it would optimize the code incorrectly:


void spinLock()
{
while(true)
{
}
}





To answer your other question, "volatile" can be used on any type, including class types.

Share this post


Link to post
Share on other sites
Volatile isn't really designed to deal with concurrency issues. It's designed to force memory reads in a situation where hardware outputs are memory mapped. All it does is force the compiler to read the variable from memory instead of caching it in a register. It does not say anything about atomicity and as such is not a replacement for concurrency primitives like mutexes and semaphores.

Share this post


Link to post
Share on other sites
volatile is a cv-qualifier like const, and can be used in every place that const can. Including in weird places like this:

struct A {
void function(void) volatile {
}
};

Share this post


Link to post
Share on other sites
Quote:
I tend to toss in that keyword when some concurrency bug occurs in hopes that that will fix it


This is by far the worst way of fixing problems.

It leads to filler variables and constructs, which only work because they introduce weird conditions which happen to work most of the time.

Access to volatile variables is slow. And it's this slowdown that will change the behavior, not the fact it's improved code.

Volatile is mandated by lock-less algorithms. Any inter-thread communication should be performed using those. They can be trivial, such as boost smart pointers, which use atomic counter updates, or complex, such as lock-less data structures.

Volatile has very limited use, and is merely a tool for developing true thread-safe structures and reliable inter-thread communication.

Quote:
...Also can it be used on complex types like class/struct instances, or just basic types?


For anything complex, I'd go with either lock-less or lock-based algorithm. With such structures, atomicity of single operations isn't even the problem anymore, but preserving consistent state of entire class/struct is, and those operations are more transactions than atomic operations.

Share this post


Link to post
Share on other sites
Another example of the use of volatile is if you are updating a variable based off a system timer that is updated by hardware (By an interrupt, perhaps?)

Because the hardware updates the variable, the complier has no way of knowing how to handle the variable, and may handle it incorrectly, or optimize it out, causing problems.

As Antheus said, this keyword does have limited use. There are only certain instances where this keyword would be needed.

The purpose of volatile is to inform the complier that this variable may be updated are modified by an outside source--such as hardware, other software, or another thread in a multi-threaded envirement. This insures the complier treats the variable, without optimizing it out, or adding anything to it.

Share this post


Link to post
Share on other sites
If I'm not mistaken, the effects of volatile aren't even defined by the standard, which doesn't address multithreading issues. The actual effect depends entirely on the compiler. The usual effect is to prevent caching the value of a variable in a register, and to make all reads and writes generate code that actually performs the loads and stores from and to memory. The standard doesn't deal with registers or memory implementation (in hardware) either.

Volatile is mainly useful in embedded systems programming, where you're dealing with memory mapped hardware, or possibly in multithreading if you really know what you're doing. For lockless data structures, volatile on its own is not enough to ensure correctness, and it really depends on the compiler and system.

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
volatile is a cv-qualifier like const, and can be used in every place that const can. Including in weird places like this:

struct A {
void function(void) volatile {
}
};

What does that do?

Share this post


Link to post
Share on other sites
Quote:
Original post by King Mir
Quote:
Original post by SiCrane
volatile is a cv-qualifier like const, and can be used in every place that const can. Including in weird places like this:

struct A {
void function(void) volatile {
}
};

What does that do?
Perhaps the 'this' pointer is volatile? Just a guess.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!