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;
};
Related
I'm trying to safely zero a std::array in a class destructor. From safely, I mean I want to be sure that compiler never optimize this zeroing. Here is what I came with:
template<size_t SZ>
struct Buf {
~Buf() {
auto ptr = static_cast<volatile uint8_t*>(buf_.data());
std::fill(ptr, ptr + buf_.size(), 0);
}
std::array<uint8_t, SZ> buf_{};
};
is this code working as expected? Will that volatile keyword prevent optimizing by compiler in any case?
The C++ standard itself doesn't make explicit guarantees. It says:
[dcl.type.cv]
The semantics of an access through a volatile glvalue are implementation-defined. ...
[Note 5: volatile is a hint to the implementation to avoid aggressive optimization involving the object because the value of the object might be changed by means undetectable by an implementation.
Furthermore, for some implementations, volatile might indicate that special hardware instructions are required to access the object.
See [intro.execution] for detailed semantics.
In general, the semantics of volatile are intended to be the same in C++ as they are in C.
— end note]
Despite the lack of guarantees by the C++ standard, over-writing the memory through a pointer to volatile is one way that some crypto libraries clear memory - at least as a fallback when system specific function isn't available.
P.S. I recommend using const_cast instead, in order to avoid accidentally casting to a different type rather than differently qualified same type:
auto ptr = const_cast<volatile std::uint8_t*>(buf_.data());
Implicit conversion also works:
volatile std::uint8_t* ptr = buf_.data();
System specific functions for this purpose are SecureZeroMemory in windows and explicit_bzero in some BSDs and glibc.
The C11 standard has an optional function memset_s for this purpose and it may be available for you in C++ too but isn't of course guaranteed to be available.
There is a proposal P1315 to introduce similar function to the C++ standard.
Note that secure erasure is not the only consideration that has to be taken to minimise possibility of leaking sensitive data. For example, operating system may swap the memory onto permanent storage unless instructed to not do so. There's no standard way to make such instruction in C++. There's mlock in POSIX and VirtualLock in windows.
According to cppreference, most uses of the volatile keyword are to be deprecated in C++20. What is the disadvantage of volatile? And what is the alternative solution when not using volatile?
There's a good talk by the C++ committee language evolution chair on why.
Brief summary, the places that volatile is being removed from didn't have any well defined meaning in the standard and just caused confusion.
Motivating (Ambiguous) Examples
Volatile bit Fields should be specified by your hardware manual and/or compiler.
Is += a single/atomic instruction? How about ++?
How many reads/writes are needed for compare_exchange? What if it fails?
What does void foo(int volatile n) mean? or int volatile foo()?
Should *vp; do a load? (This has changed twice in the standard.)
Threading
Historically, people have used volatile to achieve thread safety in C and C++. In C++11, non-UB ways to create synchronization and shared state between threads were added. I recommend Back to Basics: Concurrency as a good introduction.
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.
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
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.