Detailed description of volatile keywords in c

Source: Internet
Author: User
Tags volatile

Original net excerpt: Http://www.cnblogs.com/yc_sunniwell/archive/2010/06/24/1764231.html

The volatile reminder compiler can change the variables that are defined later, so the compiled program reads the data directly from the variable address each time it needs to store or read the variable. Without the volatile keyword, the compiler might optimize reading and storage, may temporarily use the value in the register, and if the variable was updated by another program, there would be an inconsistency. The following examples illustrate. In DSP development, it is often necessary to wait for an event to be triggered, so the program is often written like this:
Short flag;
void Test ()
{
Do1 ();
while (flag==0);
Do2 ();
}

This program waits for the value of the memory variable flag to change to 1 (suspect here is 0, a little doubt) before running Do2 (). The value of the variable flag is changed by another program, which may be a hardware interrupt service program. For example, if a button is pressed, the DSP will be interrupted, the key in the interrupt program to modify flag 1, so that the above program can continue to run. However, the compiler does not know that the value of flag will be modified by another program, so when it is optimized, the value of flag may be read into a register first, and then wait for that register to become 1. If such optimizations are unfortunate, then the while loop becomes a dead loop because the contents of the register cannot be modified by the Interrupt service program. In order for the program to read the value of the TRUE flag variable every time, it needs to be defined as follows:
volatile short flag;
It is important to note that there may be no volatile or normal operation, but it is possible to modify the compiler's optimization level and not run properly. As a result, the debug version is normal, but the release version is not a normal issue. So for security reasons, just wait for another program to modify a variable, plus the volatile keyword.

volatile is meant to be "variable."
Because the access register is faster than RAM, the compiler generally makes optimizations to reduce access to external RAM. Like what:
static int i=0;
int main (void)
{
...
while (1)
{
if (i) do_something ();
}
}
/* Interrupt Service routine. */
void isr_2 (void)
{
I=1;
}
The intent of the program is to call the Do_something function in main when the isr_2 interrupt is generated, but because the compiler determines that I is not modified in the main function, it may only perform a single read from I to a register. Then each time the if judgment uses only the "I copy" inside the register, causing the do_something to never be called. If the variable is modified with a volatile modifier, the compiler guarantees that read and write operations on this variable will not be optimized (definitely executed). I should also explain this in this example.
Generally, volatile is used in several places:
1, the change in the Interrupt service program for other programs to detect variables need to add volatile;
2, multi-tasking environment to share the logo should be added volatile;
3, Memory mapping hardware register usually also add volatile description, because each time it read and write may be different meanings;
In addition, these situations often have to consider the integrity of the data at the same time (the correlation of several signs read half interrupted rewrite), in 1 can be achieved by the shutdown interrupt, 2 can prohibit task scheduling, 3 of the hardware can only rely on good design.
Second, the meaning of volatile
Volatile is always about optimization, and the compiler has a technique calledData Flow Analysis, where variables in the parser are assigned, where they are used, where they are invalidated, analysis results can be used for constant merging, constant propagation and other optimizations, and further die code elimination. But sometimes these optimizations are not required by the program, you can use the volatile keyword to prohibit these optimizations, the literal meaning of volatile is variable, it has the following role:
1 The volatile variable is not cached in a register between two operations. In multi-tasking, interrupts, and even setjmp environments, variables can be changed by other programs, and the compiler cannot know for sure, and volatile is telling the compiler this is the case.
2 Do not do constant merging, constant propagation and other optimizations, so like the following code:
volatile int i = 1;
if (i > 0) ...
The IF condition is not treated as unconditional true.
3 reading and writing to volatile variables is not optimized. If you assign a value to a variable but it doesn't work, the compiler can often omit that assignment, but the processing of memory Mapped IO cannot be optimized.
Some people said that volatile can guarantee the atomic nature of memory operations, this is not accurate, one, x86 need lock prefix to ensure atomicity under the SMP, and second, RISC can not directly operate on the memory, to ensure that the atomicity of other methods, such as Atomic_inc.
For Jiffies, it has been declared as a volatile variable, and I think it is possible to use jiffies++ directly, and there is no need to use that complex form, because that does not guarantee atomicity.
You may not know that in Pentium and subsequent CPUs, the following two sets of instructions
Inc jiffies
;;
mov jiffies,%eax
Inc%eax
mov%eax, jiffies
function the same, but an instruction is not as fast as three instructions.
third, compiler optimization →C keyword volatile→memory break descriptor zz

"Memory" is very special, probably the most difficult part of the embedded assembly. To explain it clearly, first introduce the compiler's optimization knowledge, and then see the C keyword volatile. Finally, look at the descriptor.
1, compiler optimization Introduction
Memory access speed is far less than CPU processing speed, in order to improve the overall performance of the machine, the hardware to introduce hardware cache caches, speed up access to memory. In addition, the execution of instructions in the modern CPU is not necessarily executed in sequence, and no correlation instruction can be executed in order to make full use of the CPU's instruction pipeline and improve the execution speed. These are hardware-level optimizations. Look at software-level optimizations: One is optimized by programmers while writing code, and the other is optimized by the compiler. The commonly used methods of compiler optimizations are:caches memory variables to registers, and adjusts instruction sequences to take full advantage of CPU instruction pipelining, which is common in reordering read and write instructions. These optimizations are transparent and efficient when conventional memory is optimized. The solution to the problem caused by compiler optimizations or hardware reordering is to set the memory barrier between actions that must be performed in a particular order from the point of view of the hardware (or other processor), and Linux provides a macro to solve the compiler's order of execution issues.
void Barrier (void)
This function notifies the compiler to insert a memory barrier, but is not valid for the hardware, and the compiled code stores all the modified values in the current CPU register in memory, which is then re-read from memory when needed.
2. C keyword volatile
The C keyword volatile (note that it is used to modify variables instead of the __volatile__ described above) indicates that the values of a variable can be changed externally, so access to these variables cannot be cached to the register, which needs to be re-accessed each time it is used. This keyword is often used in multithreaded environments, because when you write multithreaded programs, the same variable can be modified by multiple threads, and the program synchronizes each thread through that variable, for example:
DWORD __stdcall ThreadFunc (LPVOID signal)
{
int* intsignal=reinterpret_cast<int*> (signal);
*intsignal=2;
while (*intsignal!=1)
Sleep (1000);
return 0;
}
The thread starts with intsignal set to 2, and then loops until intsignal exits 1 o'clock. It is obvious that the value of intsignal must be changed externally, otherwise the thread will not exit. However, the thread does not exit when it is actually running, even if it is externally changing its value to 1, look at the corresponding pseudo-assembly code to understand:
MOV ax,signal
Label
if (ax!=1)
Goto Label
For the C compiler, it does not know that this value will be modified by another thread. Naturally, it caches it in the register. Remember, the C compiler does not have a threading concept! This is where the use of volatile is needed. Volatile is intended to mean that this value may be changed outside the current thread. That is, we want to add the volatile keyword in front of the intsignal in ThreadFunc, when the compiler knows that the value of the variable changes externally, so each time the variable is accessed it is reread and the loop becomes as shown in the following pseudo-code:
Label
MOV ax,signal
if (ax!=1)
Goto Label
3. Memory
With the knowledge above it is not difficult to understand the memory modification descriptor, the memory descriptor tells GCC:
1) do not reorder the inline assembly instruction with the preceding instruction, that is, before executing the inline assembly code, the instructions before it are executed
2) do not cache variables to registers, because this code may use memory variables, and these memory variables will be changed in an unpredictable way, so gcc insert the necessary code to cache the value of the variables cached to the register back to memory, if the subsequent access to these variables, need to re-access memory.
If the assembly instruction modifies the memory, but GCC itself is not aware of, because in the output section is not described, it is necessary to add "memory" in the modification Description section, to tell the GCC memory has been modified, when GCC learned this information, will be before this command, Inserting the necessary instructions will first write back the values of the variables in the cache to the register, and then re-read them if they are to be used later.
This can also be achieved with "volatile", but instead of adding the keyword before each variable, it's better to use "memory" for easy

Detailed description of volatile keywords in c

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.