Volatile (computer programming): Difference between revisions

Content deleted Content added
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
Link suggestions feature: 2 links added.
 
(19 intermediate revisions by 8 users not shown)
Line 1:
{{Short description|A keywordKeyword used in some programming languages to tag variables}}
{{Lowercase title}}
In [[computer programming]], a [[Variable (computer science)|variable]] is said to be '''''volatile''''' if its [[Value (computer science)|value]] is a value that can be read by something else or changedmodified asynchronously by something elseother whilethan the current code[[thread is(computing)|thread runningof execution]].
The value of a <code>volatile</code> variable may spontaneously change for reasons such as:
 
sharing values with other threads;
Despite being a common keyword across many programming languages, the behavior of the <code>volatile</code> keyword differs in subtle and important ways between different programming languages. The common theme is that a <code>volatile</code> variable is a variable that may be read or modified by something outside of the current program while the current program is running. In particular, the value of a <code>volatile</code> variable may appear change spontaneously without any apparent cause from the code in the program. The typical things that can read or modify <code>Volatile</code> variables include hardware devices via [[memory-mapped I/O]] (where reading from or writing to memory is used to communicate with [[peripheral device]]s), asynchronous signal handlers, and other [[thread (computing)|threads of execution]], but not all programming languages use the <code>volatile</code> keyword for all of these examples.
sharing values with asynchronous [[signal handler]]s;
 
accessing hardware devices via [[memory-mapped I/O]] (where you can send and receive messages from [[peripheral device]]s by reading from and writing to memory).
Support for these use cases varies considerably among the programming languages that have the <code>volatile</code> keyword.
Volatility can have implications regarding function [[calling convention]]s and how variables are stored, accessed and cached.
 
Line 10 ⟶ 12:
 
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).
 
The behavior of the <code>volatile</code> keyword in C and C++ is sometimes given in terms of suppressing optimizations of an [[optimizing compiler]]: 1- don't remove existing <code>volatile</code> reads and writes, 2- don't add new <code>volatile</code> reads and writes, and 3- don't reorder <code>volatile</code> reads and writes. However, this definition is only an approximation for the benefit of new learners, and this approximate definition should not be relied upon to write real production code.
 
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>
*allowAllow access to [[memory-mapped I/O]] devices.
*allowAllow usespreserving ofvalues variablesacross betweena <code>[[setjmp|longjmp]]</code> and <code>longjmp</code>.
*allowAllow usessharing values between signal handlers and the rest of the program in <code>volatile</code> <code>sig_atomic_t</code> variables in signal handlersobjects.
 
The C and C++ standards allow writing portable code that shares values across a <code>[[setjmp|longjmp]]</code> in <code>volatile</code> objects, and the standards allow writing portable code that shares values between signal handlers and the rest of the code in <code>volatile</code> <code>sig_atomic_t</code> objects. Any other use of <code>volatile</code> keyword in C and C++ is inherently non-portable or incorrect. In particular, writing code with the <code>volatile</code> keyword for [[memory-mapped I/O]] devices is inherently non-portable and always requires deep knowledge of the specific target C/C++ implementation and platform.
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.
 
=== Multi-Threadingthreading ===
It is a common misconception that the <code>volatile</code> keyword is useful forin 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 onThe <code>volatile</code> variableskeyword 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 |date=21 September 2021 |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> MostUnlike the [[Java (programming language)|Java]] and [[C Sharp (programming language)|C#]] programming languages, operations on <code>volatile</code> variables in C and C++ compilers,are linkersnot [[atomic operation|atomic]], and runtimesoperations simplyon <code>volatile</code> variables do not providehave thesufficient necessary[[memory ordering]] guarantees (such asi.e. [[memory barrier|memory barriers]]). Most C and C++ compilers, linkers, and runtimes simply do not provide the necessary memory ordering guarantees 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. TheWith the modern C11 and C++11 standards, programmers can write portable [[thread (computing)|multi-threading]] code introducedusing new portable 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|date=21 September 2021 }}</ref>
 
===Example of memory-mapped I/O in C===
Line 207 ⟶ 211:
|}
 
=== Standards Defectsdefects ===
While intended by both C and C++, the current C standard fails to express that the <code>volatile</code> semantics refer to the lvalue, not the referenced object. The respective defect report ''DR 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>
 
=== Compiler defects ===
Unlike other language features of C and C++, the <code>volatile</code> keyword is not well supported by most C/C++ implementations - even for portable uses according to the C and C++ standards. Most C/C++ implementations are buggy regarding the behavior of the <code>volatile</code> keyword.<ref>{{Cite journal |last1=Eide |first1=Eric |last2=Regehr |first2=John |date=October 2008 |title=Volatiles Are Miscompiled, and What to Do about It |url=https://users.cs.utah.edu/~regehr/papers/emsoft08-preprint.pdf |journal=Proceedings of the Eighth ACM and IEEE International Conference on Embedded Software (EMSOFT), Atlanta, Georgia, USA |via=cs.utah.edu}}</ref><ref>{{Cite web |title=Volatile Bugs, Three Years Later – Embedded in Academia |url=https://blog.regehr.org/archives/503 |access-date=2024-08-28 |website=blog.regehr.org}}</ref> Programmers should take great care whenever using the <code>volatile</code> keyword in C and C++.
 
==In Java==
Line 214 ⟶ 221:
 
* <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.)
* There is a single global ordering of all <code>volatile</code> reads and writes. In other words, a <code>volatile</code> read will read the current value. It will(and not reada anpast olderor future value), and itall <code>volatile</code> reads will notagree readon a valuesingle fromglobal theorder futureof <code>volatile</code> writes.
* <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
{{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 provides 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]]).
 
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>
 
=== VeryEarly Oldversions Versions Ofof Java ===
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.