Work notes – CAS in simple terms

Time:2021-8-22

preface

CAS (compare and swap) is a technology commonly used to compare and replace and implement concurrent algorithms. Doug lea uses CAS technology in Java synchronizer to achieve the security of multi-threaded execution.

The idea of CAS is very simple: three parameters: the current memory value V, the old expected value a and the value B to be updated. If and only if the expected value a is the same as the memory value V, modify the memory value to B and return true. Otherwise, do nothing and return false.

problem

Onen++Problems.

Work notes - CAS in simple terms

adoptjavap -verbose Casehave a lookaddMethod

Work notes - CAS in simple terms

n++Split into several instructions:

1: ExecutegetfieldGet the original n;
2: ExecuteiaddAdd 1 operation;:
3: ExecuteputfieldWrite writes the accumulated value back to N;
The variable modified by volatile can ensure the visibility between threads, but it can not guarantee the atomic execution of these three instructions. Under the concurrent execution of multiple threads, thread safety can not be achieved and correct results can not be obtained. How should we solve it?

How to solve

Add in the add methodsynchronizedModification solution.

Work notes - CAS in simple terms

Of course, this scheme is feasible, but the performance is poor. Are there any other schemes?

Let’s look at a piece of code

Work notes - CAS in simple terms

What happens if this code is executed concurrently?

Suppose that both thread 1 and thread 2 have passed the detection of a = = 1 and are ready to perform the assignment of A. as a result, the two threads modify the variable a at the same time. Obviously, this result cannot meet the expectation and the final value of a cannot be determined.

The solution is also violent. Lock and synchronize the compareandswapint method into an atomic operation. Only one thread can modify variable a at the same time.

In addition to the low-performance locking scheme, we can also use the CAS scheme provided by JDK. In CAS, comparison and replacement are a group of atomic operations, which will not be interrupted by outside, and have more advantages in performance.

Below withAtomicIntegerTake the implementation of as an exampleCASHow to achieve it.

Work notes - CAS in simple terms

1: Unsafe is the core class of CAS. Because Java methods cannot directly access the underlying system, they need to be accessed through local methods. Unsafe is equivalent to a back door. Based on this class, you can directly operate the data of specific memory.
2: The variable valueoffset represents the offset address of the variable value in memory, because unsafe obtains data according to the memory offset address.
3: The variable value is decorated with volatile to ensure memory visibility between multiple threads.

have a lookAtomicIntegerHow to realize accumulation operation under Concurrency:

Work notes - CAS in simple terms

Suppose that thread a and thread B execute getandadd simultaneously (running on different CPUs respectively):

1: The original value of value in atomicinteger is 3, that is, the value of atomicinteger in main memory is 3. According to the JAVA memory model, thread a and thread 2 B each hold a copy of value, with a value of 3.
2: Thread a gets the value 3 through getintvolatile (VAR1, var2), and thread a is suspended
3: Thread B also obtains the value 3 through the getintvolatile (VAR1, var2) method. Fortunately, thread B is not suspended, and executes the compareandswapint method to compare the memory value to 3. The memory value is successfully modified to 2.
4: At this time, thread a recovers, performs compareandswapint method comparison, and finds that the value (3) in its own hand is inconsistent with the value (2) in memory, indicating that the value has been modified by other threads in advance, so it can only be done again.
5: Re obtain the value value. Because the variable value is modified by volatile, thread a can always see the modification of it by other threads. Thread a continues to execute compareandswapint for comparison and replacement until it succeeds.

In the whole process, CAS is used to ensurevalueThe modification of concurrency security continues to take a deep lookUnsafeClasscompareAndSwapIntMethod implementation.
Work notes - CAS in simple terms

Compareandswapint in unsafe class is a local method whose implementation is located inunsafe.cppin
Work notes - CAS in simple terms

1: First find a way to get the address of the variable value in memory
2: Compare and replace through atomic:: cmpxchg, where parameter x is the value to be updated and parameter E is the value of the original memory.

For x86 on Linux, the atomic:: cmpxchg method is implemented as follows:
Work notes - CAS in simple terms

See this compilation, heart collapse?

asmIndicates the beginning of the compilation;
volatileIndicates that compiler optimization is prohibited;
LOCK_IF_MPIs an inline function;

Work notes - CAS in simple terms

The x86 implementation of window is as follows:

Work notes - CAS in simple terms

LOCK_IF_MPIt is determined whether the current system is a multi-core processorcmpxchgInstruction additionlockPrefix.

1: For multiprocessors, prefix the cmpxchg instruction with lock.
2: Otherwise, the lock prefix is omitted( A single processor does not need the memory barrier effect provided by the lock prefix)

The Intel manual describes the lock prefix as follows:
1: Ensure the atomicity of subsequent instruction execution.
In Pentium and previous processors, instructions with lock prefix will lock the bus during execution, so that other processors cannot access memory through the bus temporarily. Obviously, this overhead is very large. In the new processor, Intel uses cache locking to ensure the atomicity of instruction execution. Cache locking will greatly reduce the execution overhead of lock prefix instructions.:
2: This instruction is prohibited from reordering with previous and subsequent read and write instructions.
3: Flush all data in the write buffer into memory.

The memory barrier effect of points 2 and 3 above ensures that CAS has the memory semantics of volatile read and volatile write at the same time.

CAS disadvantages

There is an obvious problem in CAS, that is, ABA problem.

Question: if the variable V is a when it is read for the first time, and it is checked that it is still a when it is ready for assignment, can it indicate that its value has not been modified by other threads?

If it has been changed to B and then back to a during this period, the CAS operation will mistakenly believe that it has never been modified. In this case, a marked atomic reference class is provided in the Java concurrency packageAtomicStampedReference, it can ensure the correctness of CAS by controlling the version of variable value.