How locks and atomic operations are implemented

Source: Internet
Author: User

In multi-threaded programming, the synchronization operation of a resource is the key to ensure the consistency of the resource state. The resource that needs to be synchronized can be a single simple variable or multiple variables, or some external resource. The meaning of their synchronous operation is that at the same point in time, there can be at most one thread operating these resources, that is, exclusivity. And a series of operations must be one go, the middle does not allow other threads to do related operations, which is atomicity. So we need to have a piece of code in the program that can only be executed at most one thread at a time. In Java we have the Synchronized keyword to mark a piece of code that can be executed at most one thread at any time. Lock-related classes are available in the new Java concurrent package. With lock we can achieve the same effect as synchronized. This code is usually called the critical area (Critical section).

But how did lock and synchronize come true?

It looks as if there is a switch somewhere in the code. When a thread executes to the critical section, check this switch, if it is 0 can enter, then set the switch to 1, enter, exit, set the switch to 0. It looks perfect? It's actually not that simple. Because the switch itself may be checked by multiple threads at the same time, they are simultaneously checked to 0 and entered simultaneously. Ah, this is not good. And get a switch? It seems like the endless switch doesn't solve the problem. The more talented idea is to assign your thread number to this variable, and then wait for a short period of time to check if the variable is your own process number, and if it's your own, congratulations. Wait a short period of time to prevent other threads from checking at the same time, and write the thread number after you check it. However, this wait time can be difficult to determine that the CPU thread scheduling allows the operation between the above threads is unordered and unknown. Look, this problem really seems bad through simple program tricks to solve AH. Maybe you can come up with a more genius pure software solution, but it may not be as reliable or efficient.

Software can not solve the problem, in fact, the use of hardware is easy to solve. Most CPUs provide atomic operations. Please refer to the documentation I mentioned at the beginning. The CPU guarantees that some comparisons of individual variables and exchange operations are atomic. That is, comparing a number is not what you expect, if it is, give you the variable, otherwise do not do the operation. It can be imagined that when the CPU executes such instructions, it may be necessary to pause the execution of other cores in the multicore case, to seize the bus so that the operation is not interrupted-unless a CPU cycle can be done, and the CPU cache may be cleaned ... But these are faster and more reliable than the pure software approach we mentioned above.

Well, look back to see how our Java uses CMPXCHG.

First into the Java world. Please look at Reentrantlock$fairsync.tryacquire. Have you seen a word that is synonymous with our cmpxchg? By the way, it is compareandsetstate (0, acquires). All the way down. To Unsafe.compareandswapint (for sun/oracle Java). This method is native-we have reached the edge of the Java world.

Then, let's go into the C + + world. Please find OpenJDK's unsafe.cpp. Find:

Unsafe_entry (Jboolean, Unsafe_compareandswapint (jnienv *env, Jobject Unsafe, jobject obj, jlong offset, jint E, Jint x))
Unsafewrapper ("Unsafe_compareandswapint");
OOP p = jnihandles::resolve (obj);
jint* addr = (Jint *) Index_oop_from_field_offset_long (P, offset);
Return (Jint) (Atomic::cmpxchg(x, addr, e)) = = e;
Unsafe_end

Did you find the atomic.cpp? You see a lot of pre-processing instructions for platform judgment. Ah, magical preprocessing, C language implementation of cross-platform magic weapon. As it seems, we have reached the edge of the C + + world.

Finally, the equivalent symbol of the assembly language-cpu instruction. Find a more pro-people platform, x86 under the atomic_linux_x86. inline.hpp. Yes, HPP, not here yet. S Because the world's junction with the assembler is not like a non-ventilated wall in the world of Java. The assembly can be freely embedded in C + +. We finally found the CPU instructions.

Inline Jint atomic::cmpxchg (jint exchange_value, volatile jint* dest, Jint compare_value) {
int MP = OS::IS_MP ();
__asm__ volatile (LOCK_IF_MP (% 4) "Cmpxchgl % 1, (% 3)"
: "=a" (Exchange_value)
: "R" (Exchange_value), "a" (Compare_value), "R" (dest), "R" (MP)
: "CC", "Memory");
return exchange_value;
}

Then there is the CPU micro-instructions, logic circuit, which is probably the edge of the world of software and hardware.

How locks and atomic operations are implemented

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.