Dual if magic character

Source: Internet
Author: User
Tags ibm developerworks

Transfer from IBM developerworks to China

If you find that your code runs on a single CPU for 99.99% of the time, but when you increase to two or more CPUs in proportion, it will soon crash, so this product is suitable for you.

This issue is not only related to the complexity of Java code running on a symmetric multi-processor (SMP) platform, but also to the protection of MPs) "The Impact of the Code is related. Although your code should be efficient and consistent, because platforms like SMP will exaggerate the Consistency Issues in the storage model, this is especially true when your applications run on the SMP platform.

Although the dual-If clause is a general method to solve the problems caused by multi-threaded applications, it allows you to encounter a "weak consistency" Model (CPU pipeline technology, speculative execution, etc) problems (especially about SMP systems ). Therefore, this is simply: if your application will run on the SMP system, do not use the dual-If logic in your code. Now, let's take a closer look at the causes and mechanisms of this problem.

Double if logic
First, consider the following code that points a pointer to a resource. flag indicates whether the resource exists:

If flag = 0
{
// No Resource
Set flag
Acquire Resource
Set pointer to resource
}
Else
Set pointer to resource

If this code is reentrant (that is, it can be run by multiple threads), it is very dangerous. Consider if a thread is halfway through the IF clause, and another thread finds that the flag has been set, it tries to set a pointer to the resources not allocated by the first thread, what will happen? Fortunately, this problem is easily corrected as follows:

If flag = 0
{
// No Resource
Acquire resource -----
Set pointer to resource
Set flag
}
Else
Set pointer to resource

However, now we find another problem: one thread is blocked at point A, while the other thread continues to execute because it finds that the flag is set to 0. In this case, both threads execute the same code to allocate resources-this is not what we want! However, the solution is well known: we only need to block all other threads when executing the code to obtain the resource, as shown below:

Enter lock
If flag = 0
{
// No Resource
Acquire Resource
Set pointer to resource
Set flag
}
Else
Set pointer to resource
Leave lock

(Please note that I use the lock term to keep the example simple. Of course, in Java code, the synchronous code in the synchronize clause is used to represent it ).

Currently, our code is thread-safe, but it is not efficient. It takes a lot of time to get the lock (or the pipe process (MONITOR) in Java terms), and the code in the lock is much more than what we need. To correct this, we rewrite the Code as follows:

If flag = 0
{
// No resource -----
Enter lock
Acquire Resource
Set pointer to resource
Set flag
Leave lock
}
Else
Set pointer to resource

This almost worked, but we introduced the previous problem. One thread was aborted at point A, and the other thread was inserted in, which caused CPU confusion. To correct this, we use the famous double if clause:

If flag = 0
{
// No resource -----
Enter lock
If flag = 0
Acquire Resource
Set pointer to resource
Set flag
Else
Set pointer to resource
Leave lock
}
Else
Set pointer to resource

By adding a double if clause, we have done our best to ensure the safety and efficiency of code threads. In many books on advanced programming technology, we recommend that you use double if logic to solve thread contention. However, the dual-If logic is not safe on SMP machines where multiple threads can execute simultaneously.

You will say that there is only one thread in the "locked" part of the code at a time, so what will happen? A lot! This is why we call this technique "double if magic.

For the dual if magic character, consider the impact of pipeline technology on the above Code:

Since the CPU does not see any dependencies, the code in the IF clause can be executed in any order. This will affect the instructions marked with * below.

If the flag is set to 0, calculate the pointer (which may be garbage) compared with the pointer when the flag is calculated first and then the flag is not 0) it may be more efficient to discard it. Therefore, the CPU can use the pipeline technology to process the commands marked with ** below.
The following code adds a flag to illustrate the above points:

** If flag = 0
{
// No Resource
Enter lock
If flag = 0
* Acquire resource
* Set pointer to resource
* Set flag
Else
Set pointer to resource
Leave lock
}
Else
** Set pointer to resource

Although this seems a bit strange, the above Code may be executed as follows:

** Set pointer to resource
** If flag = 0
{
// No Resource
Enter lock
Set pointer to resource
If flag = 0
* Set flag
* Acquire resource -----
* Set pointer to resource
Else

Leave lock
}
Else

As you can see, our very sensitive code is still locked, but now we have to set flag before allocating resources. Therefore, imagine that thread a is executing near point A. Another thread is coming. On the SMP machine, the second thread can be executed simultaneously on the other CPU and the first thread; this thread shows that the flag is not set to 0 (because it is outside the lock ), it can continue to direct the pointer to unallocated resources!

In addition, even if the code is executed according to what we have written, we still have no disaster relief, because the CPU can use pipeline technology to process the Code marked with ** above:

Thread a enters the locked part of the code.

Thread B evaluates the value of the first if statement and calculates the pointer value (in the final else clause ).

Thread B gets the value of "Pointer" (because thread A has not specified it, so it is garbage.

When thread a completes and unlocks, thread B calculates the value of the first if.

Unlocking causes the "flag" value to be cleared (meaning that thread B has an invalid value in its cache ).

Thread B calculates the value of the first if clause. Of course, it finds that the value is true.

Now thread B uses the garbage pointer value.

This is the Java dual if magic character. Although other languages (such as C/C ++) enable you to solve this problem by using the order in which the native functions of the language are enforced, the Java language does not work. To safely execute the preceding example, you must encapsulate all the code in a synchronize clause or look for another method.

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.