Volatile (computer programming): Difference between revisions

Content deleted Content added
The removed part is not present in the referenced article and is incorrect
Large cleanup. Fixed the introduction by mentioning that volatile is equally about reads as writes. Tried to clean up the introduction to be more accurate while still preserving the spirit of the volatile keyword in a way that is applicable to all programming languages. Also cleaned up the C/C++ and Java sections by removing unnecessary and duplicate information, and tried to make it flow better.
Tags: references removed Visual edit
Line 1:
{{Short description|A keyword used in some programming languages to tag variables}}
{{Lowercase title}}
In [[computer programming]], a '''volatile''' means[[Value that a(computer science)|value]] is pronea tovalue changethat overcan time,be outsideread theby controlsomething ofelse someor code.changed by Volatilitysomething haselse implicationswhile withinthe functioncurrent [[callingcode convention]]s,is andrunning. also impacts how variables are stored, accessed and cached.
 
InDespite thebeing [[Ca common keyword across many (programming language)|C]]languages, [[C++]],the [[Cbehavior Sharpof (programmingthe language)|C#]],<code>volatile</code> keyword differs in subtle and [[Javaimportant (programmingways language)|Java]]between different [[programming language]]s,languages. theThe common theme '''is that a <code>volatile'''</code> [[keywordvariable (computeris programming)|keyword]]a indicatesvariable that amay [[Valuebe (computerread science)|value]]or maymodified changeby betweensomething differentoutside accesses,of eventhe ifcurrent itprogram doeswhile notthe appearcurrent toprogram beis modifiedrunning. ThisIn keywordparticular, preventsthe anvalue [[optimizingof compiler]]a from<code>volatile</code> optimizingvariable awaymay subsequentappear readschange orspontaneously writeswithout andany thusapparent incorrectlycause reusingfrom athe stalecode valuein or omittingthe writesprogram. VolatileThe valuestypical primarilythings arisethat incan read or modify <code>Volatile</code> variables include hardware accessdevices via ([[memory-mapped I/O]]), (where reading from or writing to memory is used to communicate with [[peripheral device]]s), asynchronous signal handlers, and inother [[thread (computing)|threadingthreads of execution]], wherebut anot differentall threadprogramming maylanguages haveuse modifiedthe a<code>volatile</code> valuekeyword for all of these examples.
 
Volatility can have implications regarding function [[calling convention]]s and how variables are stored, accessed and cached.
Despite being a common keyword, the behavior of <code>volatile</code> differs significantly between programming languages, and is easily misunderstood. In C and C++, it is a [[type qualifier]], like <code>[[const (computer programming)|const]]</code>, and is a property of the ''[[data type|type]]''. Furthermore, in C and C++ it does ''not'' work in most threading scenarios, and that use is discouraged. In Java and C#, it is a property of a [[variable (computer science)|variable]] and indicates that the [[object (computer science)|object]] to which the variable is bound may mutate, and is specifically intended for threading. In the [[D (programming language)|D]] programming language, there is a separate keyword <code>shared</code> for the threading usage, but no <code>volatile</code> keyword exists.
 
==In C and C++==
 
In C and C++, <code>volatile</code> is a [[type qualifier]], like <code>[[const (computer programming)|const]]</code>, and is a part of a [[data type|type]] (e.g. the type of a variable or field).
 
In C, and consequently C++, the <code>volatile</code> keyword was intended to:<ref name="auto">{{cite web |title=Publication on C++ standards committee|url= http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2016.html}}</ref>
Line 14 ⟶ 16:
*allow uses of <code>sig_atomic_t</code> variables in signal handlers.
 
Loosely, the <code>volatile</code> keyword tells a C/C++ [[optimizing compiler]] to not remove reads and writes (including seemingly redundant reads and writes), and to not introduce new reads and writes, and to not change the relative order of reads and writes. For example, the [[optimizing compiler]] cannot store a value written to a <code>volatile</code> variable in a register and then use that register for a later read of the same <code>volatile</code> variable. Instead, the compiler must flush the value to main memory for every write instruction in the code, and it must fetch the value from main memory for every read instruction in the code. These strict guarantees about preserving the exact number and order of reads and writes are required to write correct code to access [[memory-mapped I/O]] devices, to write correct code using <code>[[setjmp]]</code> and <code>longjmp</code>, and to write correct code that shares values with asynchronous signal handlers.
Since variables marked as volatile are prone to change outside the standard flow of code, the compiler has to perform every read and write to the variable as indicated by the code. Any access to volatile variables cannot be optimised away, e.g. by use of registers for storage of intermediate values.
 
While intended by both C and C++, the C standards fail to express that the <code>volatile</code> semantics refer to the lvalue, not the referenced object. The respective defect report ''DR&nbsp;476'' (to C11) is still under review with [[C17 (C standard revision)|C17]].<ref>[http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2244.htm ''Clarification Request Summary for C11.''] Version 1.13, October 2017.</ref>
 
=== Multi-Threading ===
Operations on <code>volatile</code> variables are not [[atomic operation|atomic]], nor do they establish a proper happens-before relationship for threading. This is specified in the relevant standards (C, C++, [[POSIX]], WIN32),<ref name="auto"/> and volatile variables are not threadsafe in the vast majority of current implementations. Thus, the usage of <code>volatile</code> keyword as a portable synchronization mechanism is discouraged by many C/C++ groups.<ref>{{cite web |title=Volatile Keyword In Visual C++|url=http://msdn2.microsoft.com/en-us/library/12a04hfd.aspx|work=Microsoft MSDN}}</ref><ref>{{cite web |title=Linux Kernel Documentation – Why the "volatile" type class should not be used|url= https://www.kernel.org/doc/html/latest/process/volatile-considered-harmful.html|work=kernel.org}}</ref><ref>{{cite web |title=C++ and the Perils of Double-Checked Locking|url=http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf|work=DDJ|year=2004|author1=Scott Meyers |author2= Andrei Alexandrescu}}</ref>
It is a common misconception that the <code>volatile</code> keyword is useful for portable [[thread (computing)|multi-threading]] code in C and C++. Unlike the [[Java (programming language)|Java]] and [[C Sharp (programming language)|C#]] programming languages, operations on <code>volatile</code> variables in C and C++ are not [[atomic operation|atomic]]. The <code>volatile</code> keyword has ''never'' functioned as a useful, portable tool for ''any'' multi-threading scenario.<ref>{{cite web |title=Volatile Keyword In Visual C++ |url=http://msdn2.microsoft.com/en-us/library/12a04hfd.aspx |work=Microsoft MSDN}}</ref><ref>{{cite web |title=Linux Kernel Documentation – Why the "volatile" type class should not be used |url=https://www.kernel.org/doc/html/latest/process/volatile-considered-harmful.html |work=kernel.org}}</ref><ref>{{cite web |author1=Scott Meyers |author2=Andrei Alexandrescu |year=2004 |title=C++ and the Perils of Double-Checked Locking |url=http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf |work=DDJ}}</ref><ref>{{cite web |author1=Jeremy Andrews |year=2007 |title=Linux: Volatile Superstition |url=http://kerneltrap.org/Linux/Volatile_Superstition |archive-url=https://web.archive.org/web/20100620121940/http://kerneltrap.org/Linux/Volatile_Superstition |archive-date=2010-06-20 |access-date=Jan 9, 2011 |publisher=kerneltrap.org}}</ref> Most C and C++ compilers, linkers, and runtimes simply do not provide the necessary guarantees (such as [[memory barrier|memory barriers]]) to make the <code>volatile</code> keyword useful for ''any'' multi-threading scenario. Before the C11 and C++11 standards, programmers were forced to rely on guarantees from the individual implementations and platforms (e.g. POSIX and WIN32) to write [[thread (computing)|multi-threading]] code. The C11 and C++11 standards introduced new constructs such as the <code>std::atomic<T></code> templates which allowed writing portable [[thread (computing)|multi-threading]] code.<ref>{{cite web |title=volatile (C++) |url=https://msdn.microsoft.com/en-us/library/12a04hfd.aspx |work=Microsoft MSDN}}</ref>
 
===Example of memory-mapped I/O in C===
Line 45 ⟶ 46:
</syntaxhighlight>
 
However, the programmer may make <code>foo</code> mightrefer represent a ___location thatto cananother be changed by other elementselement of the computer system at any time, such as a [[hardware register]] of a device connected to the [[CPU]] which may change the value of <code>foo</code> while this code is running. The(This aboveexample does not include the details on how to make <code>foo</code> wouldrefer neverto detecta suchhardware register of a change;device withoutconnected to the CPU.) Without the <code>volatile</code> keyword, thean [[optimizing compiler]] assumeswill thatlikely convert the currentcode programfrom isthe first sample with the onlyread in the loop to the second sample without the read in the loop as part of the systemcommon that[[Loop-invariant couldcode changemotion|loop-invariant code-motion optimization]], and thus the valuecode (whichwill islikely bynever farnotice the mostchange commonthat situation)it is waiting for.
 
To prevent the compiler from optimizingdoing code asthis aboveoptimization, the <code>volatile</code> keyword iscan be used:
 
<syntaxhighlight lang="c">
Line 60 ⟶ 61:
</syntaxhighlight>
 
WithThe this<code>volatile</code> modificationkeyword prevents the loopcompiler conditionfrom willmoving notthe beread optimizedout awayof the loop, and thus the systemcode will detectnotice the expected change whento the itvariable occurs<code>foo</code>.
 
Generally, there are [[memory barrier]] operations available on platforms (which are exposed in C++11) that should be preferred instead of volatile as they allow the compiler to perform better optimization and more importantly they guarantee correct behaviour in multi-threaded scenarios; neither the C specification (before C11) nor the C++ specification (before C++11) specifies a multi-threaded memory model, so volatile may not behave deterministically across OSes/compilers/CPUs.<ref>{{cite web |url=http://kerneltrap.org/Linux/Volatile_Superstition|title=Linux: Volatile Superstition|publisher=kerneltrap.org|access-date=Jan 9, 2011|archive-url=https://web.archive.org/web/20100620121940/http://kerneltrap.org/Linux/Volatile_Superstition|author1=Jeremy Andrews|year=2007|archive-date=2010-06-20}}</ref>
 
===Optimization comparison in C===
Line 208 ⟶ 207:
|}
 
===C++11 Standards Defects ===
While intended by both C and C++, the current C standardsstandard failfails to express that the <code>volatile</code> semantics refer to the lvalue, not the referenced object. The respective defect report ''DR&nbsp; 476'' (to C11) is still under review with [[C17 (C standard revision)|C17]].<ref>[http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2244.htm ''Clarification Request Summary for C11.''] Version 1.13, October 2017.</ref>
According to the [[C++11]] ISO Standard, the volatile keyword is only meant for use for hardware access; do not use it for inter-thread communication. For inter-thread communication, the standard library provides <code>std::atomic<T></code> templates.<ref>{{cite web |title=volatile (C++)|url= https://msdn.microsoft.com/en-us/library/12a04hfd.aspx|work=Microsoft MSDN}}</ref>
 
==In Java==
TheIn all modern versions of the [[Java programming language]] also has, the <code>volatile</code> keyword, but it is used for a somewhat different purpose. When applied to a field, the Java qualifier <code>volatile</code> providesgives the following guarantees:
 
*In all versions of Java, there is a global ordering on reads and writes of all volatile variables (this global ordering on volatiles is a partial order over the larger ''synchronization order'' (which is a total order over all ''synchronization actions'')). This implies that every [[thread (computer science)|thread]] accessing a volatile field will read its current value before continuing, instead of (potentially) using a cached value. (However, there is no guarantee about the relative ordering of volatile reads and writes with regular reads and writes, meaning that it's generally not a useful threading construct.)
* <code>volatile</code> reads and writes are [[atomic operation|atomic]]. In particular, reads and writes to <code>long</code> and <code>double</code> fields will not tear. (The [[atomic operation|atomic]] guarantee applies only to the <code>volatile</code> primitive value or the <code>volatile</code> reference value, and ''not'' to any Object value.)
*In Java 5 or later, volatile reads and writes establish a [[happened-before|happens-before relationship]], much like acquiring and releasing a mutex.<ref>Section 17.4.4: Synchronization Order
* There is a single global ordering of all <code>volatile</code> reads and writes. In other words, a <code>volatile</code> will read the current value. It will not read an older value, and it will not read a value from the future.
{{cite web
* <code>volatile</code> reads and writes have "acquire" and "release" [[memory barrier]] semantics (known in the Java standard as [[happened-before|happens-before]]).<ref>Section 17.4.4: Synchronization Order
|title=The Java® Language Specification, Java SE 7 Edition
{{cite web |year=2013 |title=The Java® Language Specification, Java SE 7 Edition |url=http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.4 |access-date=2013-05-12 |publisher=[[Oracle Corporation]]}}</ref><ref>{{cite web |date=2021-03-08 |title=Java Concurrency: Understanding the 'Volatile' Keyword |url=https://dzone.com/articles/java-concurrency-understanding-the-volatile-keyword |archive-url=https://web.archive.org/web/20210509104459/https://dzone.com/articles/java-concurrency-understanding-the-volatile-keyword |archive-date=2021-05-09 |access-date=2021-05-09 |publisher=dzone.com}}</ref> In other words, <code>volatile</code> provides guarantees about the relative order of <code>volatile</code> and non-<code>volatile</code> reads and writes. In other words, <code>volatile</code> basically the same memory visibility guarantees as a Java [[lock (computer science)|synchronized block]] (but without the mutual exclusion guarantees of a [[lock (computer science)|synchronized block]]).
|url=http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.4
 
|publisher=[[Oracle Corporation]]
Together, these guarantees make <code>volatile</code> into a useful [[thread (computing)|multi-threading]] construct in [[Java programming language|Java]]. In particular, the typical [[double-checked locking]] algorithm with <code>volatile</code> works correctly in [[Java programming language|Java]].<ref>{{cite web |author1=Neil Coffey |title=Double-checked Locking (DCL) and how to fix it |url=http://www.javamex.com/tutorials/double_checked_locking_fixing.shtml |access-date=2009-09-19 |publisher=Javamex}}</ref>
|year=2013
|access-date=2013-05-12
}}</ref><ref>{{cite web
| url=https://dzone.com/articles/java-concurrency-understanding-the-volatile-keyword
| title=Java Concurrency: Understanding the 'Volatile' Keyword
| date=2021-03-08
| publisher=dzone.com
| archive-url=https://web.archive.org/web/20210509104459/https://dzone.com/articles/java-concurrency-understanding-the-volatile-keyword
| archive-date=2021-05-09
| access-date=2021-05-09}}</ref>
 
=== Very Old Versions Of Java ===
Using <code>volatile</code> may be faster than a [[lock (computer science)|lock]], but it will not work in some situations before Java 5.<ref>{{cite web
Before Java version 5, the Java standard did not guarantee the relative ordering of <code>volatile</code> and non-<code>volatile</code> reads and writes. In other words, <code>volatile</code> did not have "acquire" and "release" [[memory barrier]] semantics. This greatly limited its use as a [[thread (computing)|multi-threading]] construct. In particular, the typical [[double-checked locking]] algorithm with <code>volatile</code> did ''not'' work correctly.
|title=JSR 133 (Java Memory Model) FAQ
|url=https://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#volatile
|author1=Jeremy Manson
|author2=Brian Goetz
|date=February 2004
| archive-url=https://web.archive.org/web/20210509104707/https://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html
| archive-date=2021-05-09
|access-date=2019-11-05
}}</ref> The range of situations in which volatile is effective was expanded in Java 5; in particular, [[double-checked locking]] now works correctly.<ref>{{cite web
|title=Double-checked Locking (DCL) and how to fix it
|url=http://www.javamex.com/tutorials/double_checked_locking_fixing.shtml
|author1=Neil Coffey
|publisher=Javamex
|access-date=2009-09-19}}</ref>
 
==In C#==