Talk about C + + volatile keywords and common misconceptions

Source: Internet
Author: User
Tags int size visibility volatile

Reprint Please keep the following statement
Zhaozong
Source: https://www.cnblogs.com/zhao-zongsheng/p/9092520.html

Recently saw the definition of the volatile keyword in the C + + standard, found that the volatile keyword is completely different from Java, C + + volatile for concurrent programming basically does not help. The internet also saw a lot of misconceptions about volatile, so decided to write this article to explain in detail what the role of volatile.

Compiler-to-code optimizations

Before you talk about the volatile keyword, let's talk about compiler optimizations.

int Main () {    int0;    I++    ; " Hello World " << Endl;}

According to the code, the program reserves an int size space in memory, initializes the memory to 0, and then the data in this memory is added 1, and the last output is "Hello World" to the standard output. However, the program compiled from this code (plus the-O2 option) does not reserve an int size memory space, and does not add 1 to the number in memory. He will only output "Hello World" to the standard output.

It is not difficult to understand, this is the compiler in order to optimize the code, modify the logic of the program. In fact, the C + + standard is to allow the written code to be inconsistent with the actual generated program. While optimizing the code is a good thing, it is not possible for the compiler to arbitrarily modify the program logic, otherwise we will not be able to write reliable programs. Therefore, C + + on this logic rewrite is limited, this restriction is the compiler to modify the logic, the program to the external IO is still unchanged. How do you understand it? In fact, we can think of the program we write as a black box, and if we enter the same input in the same order, he will give the same output in the same order every time. The input and output here includes standard input and output, file system, network IO, and even some system call, and so on, everything outside the program is included. So for program users, as long as the input and output of the two black boxes is exactly the same, then the two black boxes are consistent, so the compiler can arbitrarily rewrite the logic of the program under this restriction.

The role of the volatile keyword

I don't know if I noticed that when I mentioned the input and output, I didn't mention the memory, in fact, the program does not belong to the external input and output for its own memory operation. This is why in the above example, the compiler can remove the operation of the I variable. But there is a problem, and sometimes the operating system maps some hardware into memory, allowing the program to manipulate the hardware through memory operations, such as mapping disk space to memory. Then the operation of this part of memory is actually an input and output to the outside of the program. The operation of this part of the memory can not be arbitrarily modified order, not to be ignored. This time the volatile can come in handy. In accordance with the C + + standard, the volatile variables of glvalue are manipulated, and the order and contents are unchanged as with other input and output. The result is like a volatile operation as an input or output outside the program. (Glvalue is one of the value categories, which is simply a space-allocated object in memory, see my other article for more details.) )

According to the C + + standard, this is the only feature of volatile, but in some compilers (such as, MSVC), volatile is also the function of thread synchronization, but this is the compiler's own expansion, and can not be applied across platforms.

Common misconceptions about volatile

In fact, "volatile can be synchronized between threads" is also a common misconception. For example, the following examples:

classaobject{ Public:    voidWait () {M_flag=false;  while(!M_flag)        {this_thread::sleep (1000ms); }    }    voidNotify () {M_flag=true; }Private:    volatile BOOLM_flag;}; Aobject obj;//Thread 1... obj.wait (); ...//Thread 2... obj.notify (); ...

People who misunderstand the volatile, or those who do not know about concurrent programming, may find this logic to be fine, and may think that volatile guarantees that wait () reads to M_flag, notify () writes to M_flag, so that thread 1 wakes up normally. Not really, Thread 1 may never see M_flag become true. Because in multi-core CPUs, each CPU has its own cache. There is a part of the in-memory data in the cache, and the CPU is going to operate the cache when the memory is read and stored, without directly manipulating the memory. So multiple CPUs "see" The data in the memory is not the same, this is called memory visibility problem (visibility). Under concurrent programming, a program can have multiple threads running concurrently on different CPU cores, and this time the memory visibility will affect the correctness of the program. In the example, thread 2 modifies the memory of the M_flag, but thread 1 runs on the other CPU cores, and two CPU buffers and memory are not synchronized, causing thread 1 to run on the kernel to see the old data, so thread 1 can never wake up. Memory visibility issues are not the only problem encountered in a multithreaded environment, and the chaotic execution of the CPU can also lead to unexpected events, and there is a limit to what volatile can do. These are the contents of concurrent programming, where I do not expand, in short, the volatile keyword for concurrent programming is basically not helpful.

So how can we modify the above example? C++11 began to have a very useful library, that is the atomic class template, in the <atomic> header file, multiple threads to atomic object access is secure. The following is the modified code:

 class   aobject{ public  :  void   wait () {M_flag  = false  ;  while  (! void   notify () {M_flag     = true  ;  private  : Atomic  <bool  > M_flag;};  

Just replace "volatile bool" with "atomic<bool>". The <atomic> header file also defines a number of commonly used aliases, such as "atomic<bool>", which can be replaced with "Atomic_bool". The atomic template overloads the usual operators, so atomic<bool> is not very different from ordinary bool variables. Some of the advanced uses of atomic, because of the memory model of C + + and concurrent programming, I did not expand this, and later have time to fill up.

Talk about C + + volatile keywords and common misconceptions

Related Article

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.