Start by introducing a blog post:
1. Why use volatile?
The volatile keyword and the const counterpart in C + +, which are used to modify variables, are often used to establish language-level memory barrier. This is a description of the volatile modifier for BS in "the C + + programming Language":
A volatile specifier is a, hint to a compiler, that an object, its value in ways not specified by the language so That aggressive optimizations must is avoided.
The volatile keyword is a type modifier that declares a type variable that can be changed by factors unknown to the compiler, such as the operating system, hardware, or other threads. When you encounter a variable declared by this keyword, the compiler will no longer optimize the code that accesses the variable, providing stable access to the special address. Declaration-time syntax:int volatile vInt; when the value of a variable declared with a volatile is required, the system always reads the data back from its memory, even if the preceding instruction has just read the data from there. And the read data is saved immediately. For example:
4 |
// 其他代码,并未明确告诉编译器,对 i 进行过操作 |
Volatile indicates that I is subject to change at any time and must be read from the address of I each time it is used, so the compiler generated assembly code will re-read the data from I's address in B. The optimization approach is that since the compiler found that the code between the I-read data two times does not operate on I, it automatically places the last-read data in B. Instead of re-reading from inside I. Thus, if I is a register variable or represents a port data is prone to error, so volatile can guarantee a stable access to the special address. Note that in VC 6, the General debug mode is not optimized for code, so the role of this keyword can not be seen. This is done by inserting assembly code to test for the effect of a volatile keyword on the final code of the program:
Enter the following code:
10 |
// 下面汇编语句的作用就是改变内存中 i 的值 |
13 |
mov dword ptr [ebp-4], 20h |
Then, running the program in Debug version mode, the output is as follows:
i = 10
i = 32
Then, running the program in Release version mode, the output is as follows:
i = 10
i = 10
The results of the output clearly indicate that the compiler optimized the code in Release mode and did not output the correct I value for the second time. Next, let's add the I statement to the volatile keyword to see what's changed:
10 |
mov dword ptr [ebp-4], 20h |
Run the program in Debug and release versions, respectively, with the output being:
i = 10
i = 32
This indicates that the volatile keyword has played its part. In fact, not just the "inline assembly manipulation Stack" is a compilation of unrecognized variable changes, and more likely to be multi-threaded concurrent access to shared variables, a thread changed the value of the variable, how to let the changed value to other threads visible. Generally, volatile is used in several places:
1) Variables modified in the Interrupt service program for other programs need to be volatile;
2) The signs shared between tasks in a multi-tasking environment should be volatile;
3) The hardware registers of the memory map are usually also given a volatile description, because each time it is read and written can be different meanings;
2.volatile pointer
Like the const modifier, const has a constant pointer and pointer constant, and volatile has a corresponding concept:
-
Decorates The object pointed to by the pointer, the data is const or volatile:
const
char
* cpch;
2 |
< Code class= "Bold keyword cpp" >volatile char * vpch; |
Note: For VCs, this feature implementation is safe after VC 8.
The value of the pointer itself--an integer variable representing the address, is const or volatile:
Note:(1) You can assign a non-volatile int to a volatile int, but you cannot assign a non-volatile object to a volatile object.
(2) In addition to the basic type, the user-defined type can also be decorated with a volatile type.
(3) A class with a volatile identifier in C + + can access only a subset of its interfaces, a subset controlled by the class's implementation. The user can only use Const_cast to obtain full access to the type interface. In addition, volatile is passed from the class to its members as a const.
3. Volatile under multi-threading
Some variables are declared with the volatile keyword. When two threads are going to use a variable and the value of the variable is changed, it should be declared with a volatile keyword that prevents the optimizer compiler from loading the variable from memory into the CPU register. If a variable is loaded into a register, then two threads are likely to use a variable in memory, one to use a variable in the register, which causes the program to execute incorrectly. Volatile means that the compiler must actually take the variable out of memory each time it is manipulated, rather than using the value in the register already in existence, as follows:
Volatile BOOL bstop = FALSE;
(1) in one thread:
while (!bstop) {...}
bstop = FALSE;
Return
(2) In another thread, terminate the thread loop above:
bstop = TRUE;
while (bstop); Wait for the above thread to terminate, if Bstop does not use the volatile declaration, then this loop will be a dead loop, because Bstop has been read into the register, the value of bstop in the register will never become false, plus volatile, when the program executes, Each time you read the value of bstop from memory, the loop is not dead.
This keyword is used to set the storage location of an object in memory, not in the register。 Because a generic object compiler might place its copy in a register to speed up the execution of instructions, such as in the following code:
...
int nmycounter = 0;
for (; nmycounter<100;nmycounter++)
{
...
}
...
In this code, the copy of Nmycounter may be stored in a register (loop, the test and operation of the Nmycounter is always in the value of this register), but there is another piece of code that performs this operation: nmycounter-= 1; The change to Nmycounter is the operation of the in-memory nmycounter, so there is a phenomenon: Nmycounter's change is out of sync.
Address of the above blog: https://www.cnblogs.com/yc_sunniwell/archive/2010/07/14/1777432.html
I'll cite the C + + programming Language here again:
Two representations of a meaning:
(1) The volatile specifier is used to indicate, a object can be modified by something external to the thread of CONTR Ol.
For example:
volatile const long Clock_register; Updated by the hardware clock
A volatile specifier basically tells the compiler not to optimize away apparently redundant reads and writes. For example:
Auto T1 {clock_register};
... not use of the clock_register here ...
Auto T2{clock_register};
Had Clock_register not been volatile, the compiler would has been perfectly entitled to eliminate one of the reads and as sume T1 = = t2.
(2) A volatile tells the compiler, the value of an object can be changed by something .
Precautions:
Do not use the volatile except in low-level code, deals directly with hardware.
Do not assume the volatile have special meaning in the memory model. It does not. It is not-as in some latter languages-a synchronization mechanism. To get synchronization,
Use an atomic, a mutex, or a condition_variable.
Further instructions on atomic (extracted from Cppreference):
Within a thread of execution, accesses (reads and writes) through volatile glvalues cannot be reordered past Obser Vable side-effects (including other volatile accesses) that is sequenced-before or Sequenced-after within the same thread, but this order isn't guaranteed to being observed by another thread, since Volatile access does not establish Inter-thread synchronization.
In addition, volatile accesses was not atomic (concurrent read and write is a data race) and does not order memory (non- Volatile memory accesses may be freely reordered around the volatile access).
One notable exception is Visual Studio, where, with default settings, every volatile write have release semantics and every Volatile read has acquire semantics (MSDN), and thus volatiles is used for Inter-thread synchronization. Standard volatile semantics is not applicable to multithreaded programming, although they is sufficient for e.g. communication with a std::signal handler, runs in the same thread, applied to sig_atomic_ T variables.
A simple description of volatile in C + + +