When are const volatile objects necessary in C++?
Note: I do understand the need for pointers to const volatile memory locations, but those don't require the objects themselves to be const or volatile.
I'm asking about objects that are themselves of some const volatile type, for example:
const volatile T obj;
In which situations are these necessary or useful?
The situations are rare where when you actually need volatile in c++. volatile is not useful for multithreaded any more. From this website there are only three portable uses of volatile.
Hans Boehm points out that there are only three portable uses for volatile. I'll summarize them here:
marking a local variable in the scope of a setjmp so that the variable does not rollback after a longjmp.
memory that is modified by an external agent or appears to be because of a screwy memory mapping
signal handler mischief
So basically you want to really only use other features for concurrent programming and save volatile for those rare situations
Related
It seems like the volatile comparison functions in shared_ptr implementation do not exist.
Does it even make sense to exist?
Essentially no, the standard doesn't cater for comparisons or boolean conversion on a volatile shared_ptr.
The following fails to compile...
auto main() -> int {
volatile shared_ptr<int> a;
if (a == nullptr) // fails
; // empty
if (a) // fails
; // empty
}
You could cast the volatile off (via. a const_cast), but I'm not sure that will have the desired outcome. From the cppreference:
Modifying a const object through a non-const access path and referring to a volatile object through a non-volatile glvalue result in undefined behavior.
In more general terms, in not marking member methods as volatile, the class or library implementors are effectively saying "this is not intended to be use as a volatile object" - if it were, then the appropriate methods or overloads would provide for volatile objects. Similarly, this applies to const, in marking members as const, they are saying "this class can be used as a const object.
Why is the volatile needed, what external sources could be modifying the shared_ptr "without the knowledge of the compiler" (this is one of the uses of volatile)? If there are threading issues, then you would be better served with one the thread library utilities, or if the requirement is simply turning off optimisations, various compilers have mechanisms for this already (pragmas etc.).
Volatile is just an indication to the compiler that the memory may change unexpectedly. Turns off some optimizations. Under the covers its just a memory address.
The shared pointer is just holding/managing the resource. That said, since std::shared_ptr::get() isn't marked volatile, you cannot really use a shared_ptr to manage a volatile pointer in a accessible way.
I'd recommend using a naked pointer, and using scoped exit or the destructer to clean up after it.
If you are using volatile because the pointer may be modified by another thread, you may want to consider using std::atomic instead of volatile. In threading workflows, before std::atomic, pointers that were accessed from other threads were usually marked volatile. That is no longer best practice.
This question already has answers here:
When to use volatile with multi threading?
(5 answers)
Closed 8 years ago.
I have a variable which is shared between several threads (assuming suitable sync method is in place).
Should I define the variable as volatile?
The reason that I am asking is: Any of the following can be the answer:
yes: Since the variable can be change by a thread and other thread should be aware of it.
no: Since compiler can understand that a value for a variable is on CPU memory and it doesn't matter which thread wants to read it, compiler would take care of it.
If you have suitable synchronization in place, then there is no need for volatile.
If you do not have suitable synchronization in place, then volatile does not supply suitable synchronization, although in some C++ implementations it might appear to help to a greater or lesser extent.
Generally, you should only use volatile if a library API requires it (e.g. atomic operations on Windows).
There are cases in very low level programming dealing with hardware where volatile can be required.
volatile is (nearly) useless for a multithreaded application programming. It was intended for use when interfacing with memory-mapped hardware. Although C++ Standard is silent about volatile in terms of Acquire or Release semantics on variables some specific platforms however do add additional functionality or restrictions to what volatile does. For example, in Windows 2010 (at least) Acquire and Release semantics do apply to certain operations on volatile variables:
Microsoft Specific
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.
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.
http://msdn.microsoft.com/en-us/library/12a04hfd%28v=vs.100%29.aspx
If I have a C++ method declaration as follows:
class A
{
public:
double getPrice() volatile;
};
What does volatile represent here?
What could it be used for?
You might be interested in this Dr Dobbs article by Andrei Alexandrescu. I was :)
Edit:
That article was written a while back and now it seems that the community has moved on. Herb Sutter has this to say this. Thanks Iain (and Herb!)
mlimber points out that Andrei had a follow up article here where he continues to advocate the use of volatile correctness as a valuable tool for detecting race conditions on systems supporting POSIX-like mutexes.
You're probably familiar with const methods and const-correctness (cf. "Item 15 - Use const proactively" in C++ Coding Standards by Sutter and Alexandrescu), and volatile works in similar but slightly different ways to yield what might be called "volatile-correctness."
Like const, volatile is a type modifier. When attached to a member function as in your example, either modifier (or both!) mean that the object on which the method is called must have or be convertible to that type.
Consider:
struct A
{
void f();
void cf() const;
void vf() volatile;
void cvf() const volatile;
// ...
};
void foo( A& a, const A& ca, volatile A& va, const volatile A& cva )
{
a.f(); // Ok
a.cf(); // Ok: Can convert non-const obj to const obj
a.vf(); // Ok: Can convert non-volatile obj to volatile obj
a.cvf(); // Ok: Can convert non-cv obj to cv obj
ca.f(); // Error: can't call non-const method on const obj
ca.cf(); // Ok
ca.vf(); // Error: can't call non-const method on const obj
ca.cvf(); // Ok: Can convert
va.f(); // Error: can't call non-volatile method on volatile obj
va.cf(); // Error: can't call non-volatile method on volatile obj
va.vf(); // Ok
va.cvf(); // Ok: Can convert
cva.f(); // Error: can't call non-cv method on cv obj
cva.cf(); // Error: can't call non-cv method on cv obj
cva.vf(); // Error: can't call non-cv method on cv obj
cva.cvf(); // Ok
}
Note these are compile-time errors, not run-time errors, and that is where it's potential usefulness comes in.
Const-correctness prevents unintentional errors at compile-time as well as making code "easier to understand, track, and reason about" (Sutter and Alexandrescu). Volatile-correctness can function similarly but is much less used (note that const_cast in C++ can cast away const, volatile, or const volatile, but rather than calling it cv_cast or similar, it's named after const alone because it is far more commonly used for casting away just const).
For instance, in "volatile - Multithreaded Programmer's Best Friend", Andrei Alexandrescu gives some examples of how this can be used to have the compiler automatically detect race conditions in multithreaded code. It has plenty of explanation about how type modifiers work, too, but see also his follow-up comments in his subsequent column.
Update:
Note that C++11 changes the meaning of const. Thus sayeth the Sutter: "const now really does mean 'read-only, or safe to read concurrently'—either truly physically/bitwise const, or internally synchronized so that any actual writes are synchronized with any possible concurrent const accesses so the callers can’t tell the difference."
Elsewhere, he notes that while C++11 has added concurrency primitives, volatile is still not one of them: "C++ volatile variables (which have no analog in languages like C# and Java) are always beyond the scope of this and any other article about the memory model and synchronization. That’s because C++ volatile variables aren’t about threads or communication at all and don’t interact with those things. Rather, a C++ volatile variable should be viewed as portal into a different universe beyond the language — a memory location that by definition does not obey the language’s memory model because that memory location is accessed by hardware (e.g., written to by a daughter card), have more than one address, or is otherwise 'strange' and beyond the language. So C++ volatile variables are universally an exception to every guideline about synchronization because are always inherently “racy” and unsynchronizable using the normal tools (mutexes, atomics, etc.) and more generally exist outside all normal of the language and compiler including that they generally cannot be optimized by the compiler.... For more discussion, see my article 'volatile vs. volatile.'"
It is a volatile member which, just like a const member can only be called on const objects, can only be called on volatile objects.
What's the use? Well, globally volatile is of little use (it is often misunderstood to be applicable for multi-threaded -- MT -- programming, it isn't the case in C++, see for instance http://www.drdobbs.com/high-performance-computing/212701484), and volatile class objects are even less useful.
IIRC A. Alexandrescu has proposed to use the type checking done on volatile objects to statically ensure some properties usefull for MT programming (say that a lock has been taken before calling a member function). Sadly, I don't find the article back. (Here it is: http://www.drdobbs.com/184403766)
Edit: added links from the comments (they where added also in the question).
In member functions (the only functions that can have cv-qualifiers), the const or volatile effectively modifies the this pointer. Therefore, like a const member function can access the object only as if through a const pointer, a volatile member function can access the object only as if through a volatile pointer.
The informal meaning of volatile is that an object can change due to circumstances outside the program (such as memory-mapped I/O or shared memory). The precise meaning is that any access to volatile data must be done in reality as it is written in the code, and may not be optimized out or changed in order relative to other volatile accesses or I/O operations.
What this means is that any operations relating to the object in volatile member functions must be done in order as written.
Further, a volatile member function can only call other volatile (or const volatile) member functions.
As for what use it is...frankly, I can't think of a good use right now. volatile is vital for some data objects, such as pointers pointed to I/O registers, but I can't think of why a volatile member function would be useful.
I have a class A that I overload its operator=. However it is required that I need to do something like this:
volatile A x;
A y;
x = y;
which raised an error while compiling
error: no operator "=" matches these operands
operand types are: volatile A = A
If I removed volatile, it's compilable. Is there anyway to have this compiled without removing the "volatile" (and still keep the behavior of volatile) ?
Basically this is a CUDA program in which 'x' is a shared memory ( all threads can access and modify its value ). I want it to be "volatile" in order to avoid the compiler optimization and re-use the value instead of accessing the memory address.
More on the problem: at the beginning A is just a primitive type e.g integer, volatile worked as expected and doesn't cause any problem, now I want it to be a custom class ( integer 128-bit for example ). I'm not sure why C++ complain in this case but not with primitive data type.
Thanks in advance.
Assuming the volatile qualification is necessary, you'll have to add a volatile assignment operator to A (A& A::operator=(const A&) volatile).
const_cast<A&>(x) = y will make it compile, but will technically cause undefined behaviour, and will certainly remove the guarantees that volatile gives.
The "volatile isn't a lot of use in C++ threading" comment is irrelevant to the question, which is CUDA-specific. volatile is needed for warp synchronous coding in CUDA.
volatile isn't a lot of use in C++ threading (see Dave Butenhof's explanation at http://www.lambdacs.com/cpt/FAQ.html#Q56). It's not sufficient to ensure your program flushes the data written out of core-local cache to a point where other programs can see the updates in shared memory, and given almost everyone's multi-core these days, that's a serious problem. I suggest you use proper threading synchronisation methods, such as boost's if your portability needs match it, or perhaps POSIX mutexes and condition variables, failing that more architecture dependent techniques like memory barriers or atomic operations that implicitly sync memory between cores.
I'm sure you want it to be fast, but fast and unstable isn't generally as useful as slow and reliable, especially if you ship a product that's only unstable on your customer's hardware.
Declaring a copy constructor
volatile A& operator=(volatile A&) volatile;
worked for me with nvcc. Note that you may have to pass around the non-primitive type by reference only. Else you'll need more copy-constructors that convert volatile instances to non-volatile whenever the non-primitive type is passed by value to a non-volatile parameter.
It really boils down to establishing volatile-correctness (much like const-correctness).
From what I've read from Herb Sutter and others you would think that volatile and concurrent programming were completely orthogonal concepts, at least as far as C/C++ are concerned.
However, in GCC implementation all of std::atomic's member functions have the volatile qualifier. The same is true in Anthony Williams's implementation of std::atomic.
So what's deal, do my atomic<> variables need be volatile or not?
To summarize what others have correctly written:
C/C++ volatile is for hardware access and interrupts. C++11 atomic<> is for inter-thread communication (e.g., in lock-free code). Those two concepts/uses are orthogonal, but they have overlapping requirements and that is why people have often confused the two.
The reason that atomic<> has volatile-qualified functions is the same reason it has const-qualified functions, because it's possible in principle for an object be both atomic<> and also const and/or volatile.
Of course, as my article pointed out, a further source of confusion is that C/C++ volatile isn't the same as C#/Java volatile (the latter is basically equivalent to C++11 atomic<>).
Why is the volatile qualifier used throughout std::atomic?
So that volatile objects can also be atomic. See here:
The relevant quote is
The functions and operations are defined to work with volatile objects, so that variables that should be volatile can also be atomic. The volatile qualifier, however, is not required for atomicity.
Do my atomic<> variables need to be volatile or not?
No, atomic objects don't have to be volatile.
As const, volatile is transitive. If you declare a method as volatile then you cannot call any non-volatile method on it or any of its member attributes. By having std::atomic methods volatile you allow calls from volatile member methods in classes that contain the std::atomic variables.
I am not having a good day... so confusing... maybe a little example helps:
struct element {
void op1() volatile;
void op2();
};
struct container {
void foo() volatile {
e.op1(); // correct
//e.op2(); // compile time error
}
element e;
};