C/C ++:
The compiler optimizes program commands during program compilation, such as changing the execution sequence of some commands or copying the values of variables to registers, then, you can quickly obtain the value from the register in subsequent use.
However, these optimization behaviors may cause a data competition in the critical section in a multi-threaded environment. Imagine that both threads A and B are accessing a variable C. When a accesses variable C, the compiler optimized and copied the value of C to the register for the standby access. The problem is that if B changes the value of the C variable, and a still accesses the cached value, data inconsistency may occur.
The volatile modifier tells the compiler not to optimize the variable, but it is not enough to synchronize the thread because it lacks atomic and ordered semantics. For example, the I ++ operation is actually composed of three operations. First, the value is loaded into the register from the memory, then the value is added to 1, and then written to the Register, because volatile does not have atomic semantics, variable I declared with volatile still faces data inconsistency in multi-threaded environments.
Volatile has no sequential statements, so the operations of the Variable Design he declares may be rearranged to improve performance, which may lead to a data competition.
Java: volatile in Java is more powerful than C and C ++, and incomplete sequence semantics are added after 1.5: 1. when reading the volatile variable, the read operation must be completed after the current read operation is complete. 2. When writing the volatile variable, the operation before this operation must be completed before this operation can be executed.
This incomplete sequence semantics allows the volatile variable in Java to be used for state flag created by multiple threads.
C # is similar to Java.
To sum up, volatitle is relatively weak in thread synchronization.