
Code Xiaobian MillionFans CertifiedAccount
By clicking follow, you not only gain a tool for finding resources but also an interesting soul ▶ ▶ ▶
When learning C language, there is a strange keyword ‘volatile’. What is its use?
volatile and the Compiler
First, let’s look at this piece of code:
int busy = 1;
void wait() { while(busy) { ; }}
Compile it, and note that, we are using O2 optimization:
Let’s take a closer look at the generated assembly:
wait: mov eax, DWORD PTR busy[rip].L2: test eax, eax jne .L2 retbusy: .long 1
Here, the L2 part corresponds to the while loop. This instruction is optimized by the compiler, and we can see that whether we can exit the loop is determined by checking the register eax, rather than checking the actual content of the variable busy in memory.Note that for this piece of code, this optimization is correct, but the problem is that if there is other code modifying the variable busy, then this optimization will cause the modifications made by other code to the variable busy to not take effect at all, like this:
int busy = 1; // This function runs in thread A
void wait() { while(busy) { ; }} // This function runs in thread B
void signal() { busy = 0;}
If the machine instructions corresponding to the while loop in the wait function only read data from the register, then even if the signal function in thread B modifies the busy variable, it cannot make the wait function exit the loop.If you use the volatile modifier on the busy variable, the generated instructions will change to this:
wait:.L2: mov eax, DWORD PTR busy[rip] test eax, eax jne .L2 retbusy: .long 1
Notice that at this time, the L2 part reads data from the memory where the busy variable is located and stores it in eax every time, and then checks it, ensuring that we can read the latest value of the busy variable each time.In fact, you can think of the register eax as a cache for the memory where busy is located. When the cache (register) and the data in memory are consistent, there will be no problem, but when the cache and the data in memory are inconsistent (that is, the memory has been updated but the cache still holds the old data), the program’s operation is often unexpected.In addition to the multithreading example, there is another case where a signal handler or hardware modifies the variable (which is often encountered when interacting with hardware in C language). If the compiler generates instructions like those at the beginning of this article, then the waiting thread will not detect the modifications made by the signal handler or hardware to the variable.
Therefore, we need to tell the compiler: “Don’t be clever, don’t just read data from the register; this variable may have been modified elsewhere, so get the latest data from memory when using it.”Now it’s time to summarize briefly, volatile only prevents the compiler from trying to optimize the reading operation of the variable.
volatile and Multithreading
It is important to note that volatile only ensures the visibility of the variable, but has nothing to do with atomic access to the variable; these are two completely different tasks.Assuming there is a very complex structure struct foo:
struct data { int a; int b; int c; ...};volatile struct data foo; void thread1() { foo.a = 1; foo.b = 2; foo.c = 3; ...}void thread2() { int a = foo.a; int b = foo.b; int c = foo.c; ...}
Using volatile to modify the variable foo only ensures that when this variable is modified by thread1, we can read the latest value in thread2, but this does not solve the problem of atomic access to foo needed for concurrent read and write in multithreading.To ensure atomic access to a variable, locks are generally used. When using locks, the lock itself already contains the capabilities provided by volatile, that is, ensuring the visibility of the variable. Therefore, when using locks, there is no need to use volatile.
volatile and Memory Order
Some may wonder if I want to use a volatile-modified variable that is not that complex, just an int, like this:
volatile int busy = 0;
Thread A reads the busy variable, and thread B updates the busy variable. When A detects a change in busy, it performs a specific operation. Is this feasible? Since using volatile ensures that we read busy from memory each time, it should be usable this way.However, while the concept of computers may be relatively simple, the engineering practice is complex.We know that due to the significant speed difference between the CPU and memory, there is a layer of cache between the CPU and memory. The CPU does not directly read memory; the existence of the cache complicates the issue. Due to space constraints and the theme of this article, we will not elaborate further.To optimize memory read and write, the CPU may reorder memory read and write operations, leading to the consequence that: suppose in thread 1, lines N and N+1 of code are executed in order, but in thread 2, line N+1 appears to take effect first. Suppose the initial value of X is 0, and Y is 1:
Thread 1 Thread 2
X = 10 if (!busy)
busy = 0; Y = X;
When thread 2 detects that busy is 0 and reads the value of X, it may read 0.To solve this problem, we need not volatile; volatile cannot solve the reordering problem. We need a memory barrier.A memory barrier is a type of machine instruction that restricts the processor’s memory operations before and after the barrier instruction, ensuring that reordering issues do not occur.The effect of a memory barrier still encompasses the functionality provided by volatile, so volatile is also unnecessary.It can be seen that in a multithreaded environment, we almost never use the volatile keyword.
High-quality original review
The most difficult IT company to get hired in China…
Elon Musk privately messaged a beautiful internet celebrity to have his child, and after being rejected, cut off her $21,000 advertising income every two weeks?
A colleague from outsourcing attended a dinner, and just as he arrived at the door of the private room, he heard the supervisor say: “We are all insiders, in the future, any dirty or tiring work will be given to outsourcing; they are here to serve us, don’t feel embarrassed.”
After leaving the job, a bug appeared online, and the interface was developed by myself; the n+1 compensation was reclaimed.
Heard that the internet doesn’t care about age 35 anymore?
Programmers start “defensive programming” to protect their jobs…..
This move by ByteDance directly changed everyone’s habits?
Huawei employees revealed: Most people in OD are at their peak upon joining! Level D4, except for a 3k monthly salary increase when promoted to D5, has never increased at any other time.

Don’t forget to share, bookmark, and like!