Thread 4 synchronization and deadlock

Source: Internet
Author: User

Threads can improve the efficiency of the program in some way (concurrent execution, saving time.) ), but it also produces some side effects (data dirty read, deadlock).

Data dirty reading can be controlled by synchronous technology, and deadlock is resolved by convention.

Class increment//synchronization to resolve dirty reads
{
private int n = 0;
private int Max;
Public Increment (int max)
{
This.max = max;
}
public int Result
{
Get
{
return n;
}
Set
{
n = value;
}
}
public void Inc ()
{
for (int i = 0; i < max; i++)
{
n++;//Replace with interlocked.increment (ref n); implement synchronous execution
}
}
}
Class Program
{
public static void Main ()
{
Increment inc = new Increment (10000);
thread[] threads = new THREAD[30];
for (int i = 0; i < threads. Length; i++)
{
Threads[i] = new Thread (inc. INC);
Threads[i]. Start ();
}
for (int i = 0; i < threads. Length; i++)//synchronous technology that enables threads to execute one at a. Avoid dirty reading.
{
Threads[i].  Join (); Wait for 30 threads to finish executing
}
Console.WriteLine (Inc.result); Value of output n

}

}


The basic function of the above program is to use the Increment Inc method to increment Max for N, which differs from starting 30 threads in the main method and executing the INC method at the same time. In this example, Max has a value of 10000 (passed in through the increment construction method). The reader can run this program, the normal result should be 300000, but usually do not get this result, generally get the result is less than 300000. The reason for this is the n++ in the Inc method, although on the surface, n++ is just a simple self-amplification language, but from the underlying analysis, the n++ IL code is as follows:

LDSFLD//Get the initial value of N and press it into the method stack

ldc.i4.1//Pressing 1 into the method stack

Add//POPs the top two values from the method stack, adds them, and saves the results in the method stack

STFLD//POPs a value from the current method stack and updates the class field N

For each IL statement above is thread-safe, but n++ this C # statement requires four steps above to complete, n++ this statement is not thread-safe. So-called "dirty" data occurs whenever any step before executing the stfld instruction is interrupted by another thread acquiring the CPU.

Assuming that the initial value of n is 0, After Thread1 executed ldc.i4.1 after the thread2 interrupt (the add instruction is not executed), then the initial value of the THREAD2 obtained n is still 0, assuming that thread2 smooth execution, then the value of n is already 1, when the thread2 execution, Thread1 continue to execute the add refers to , and Thread1 is executed successfully, the execution result n in Thread1 is still 1. Therefore, this also occurs when the call two times N++,n is still 1. The way to solve this problem is also very easy to think of, is to let the above four IL statements do not execute, to execute is all done, this is a bit of transactional meaning.

The technique of solving this problem in C # is called Synchronization. The essence of synchronization is to lock a block of code so that it becomes a whole and is a common retreat. The simplest thing to do is lock the code block with lock. This statement has been used more than once in the previous few words. The lock statement can lock any object, if the lock is a class member, directly using the form of lock (obj), if the lock is a static member, you can put the lock master on the object type, the code is as follows:

Lock (typeof (Staticclass))

{

... ...

}

For the increment class, we can lock the n++, or Lock the Inc method, such as the code for the increment class that locks the n++ as follows:

Class Increment
{
private int n = 0;
private int Max;
Private Object lockn = new Object ();
Public Increment (int max)
{
This.max = max;
}
public int Result
{
Get
{
return n;
}
Set
{
n = value;
}
}

private void Incn ()
{
Lock (LOCKN)
{
n++;
}
}
public void Inc ()
{
for (int i = 0; i < max; i++)
{
INCN ();
}
}
}


You can also put the following code directly in the for loop instead of calling the Incn method,

Lock (LOCKN)
{
n++;
}

or lock the INC method directly, the code is as follows:

public void Inc ()
{
Lock (LOCKN)
{
for (int i = 0; i < max; i++)
{
n++;
}
}
}

However, I do not recommend directly to the INC lock, because this and single-threaded no difference, although you can avoid the occurrence of dirty data, but the cost of efficiency.

From this example analysis, the cause of the problem is that n++ is not an atomic operation. A interlocked class is provided in the. NET Framework to make n++ atomic. Interlocked has some methods to ensure that the operation of the variable is atomic, such as the increment method to ensure that the operation of the n++ is atomic, the decrement method guarantees that the operation of the n--is atomic, and the Exchange method guarantees that the operation of the variable assignment is atomic. Therefore, you can use the Increment method to replace n++ with the following code:

public void Inc ()
{
for (int i = 0; i < max; i++)
{
Interlocked.Increment (ref N);
}
}


Everything has two sides, synchronous technology is no exception, in some cases, can be caused by two of threads lock some objects with each other to create a deadlock (that is, two threads waiting for each other to release the object). It's like there are two students in the evening to review their lessons, they all want to learn to surpass each other, and they are very tired, but who will not rest, are staring at each other's house lights, expect each other after rest. Himself to rest. But no one would turn off the lights first, so that's all they had to do. Of course, there are two ways to solve this problem, the first is that one of the students or two students do not care whether the other person first to sleep, their learning is tired of the direct turn off the lights. Of course, another method is a bit of violence, that is, the direct power outage, then who also do not learn (this is equivalent to thread interruption, but not the best to do not use this trick).

Let's start with an example of a thread deadlock, the code is as follows:

Class Program
{
private static Object Obja = new Object ();
private static Object OBJB = new Object ();
public static void Locka ()
{
Lock (Obja)
{
Thread.Sleep (1000);
Lock (OBJB)
{
}
}
Console.WriteLine ("Locka");
}
public static void Lockb ()
{
Lock (OBJB)
{
Thread.Sleep (2000);
Lock (Obja)
{
}
}
Console.WriteLine ("Lockb");
}
public static void Main ()
{
Thread Threada = new Thread (Locka);
Thread threadb = new Thread (LOCKB);
Threada.start ();
Threadb.start ();
}
}


In the above code, the Locka method will delay 1 seconds after execution of lock (Obja) in the current thread, and the LOCKB method will delay 2 seconds after execution of lock (OBJB), generally locka will perform lock (OBJB) First, but OBJB is locked by lockb , and the lockb is still delayed (2 seconds not yet). At this point, Locka has locked obja and OBJB, and when LOCKB executes to lock (Obja), Obja is blocked because lockb has been locked. While the Locka is executing to lock (OBJB), OBJB is also locked because Locka is still delayed. Locka and lockb are equivalent to the above two students, waiting for each other to turn off the lights, but no one will turn off the lights, so it is dead lock. If the first method is very simple, it is to keep the order of multiple objects that are locked, such as changing the lock order of the LOCKB method, the code is as follows:

public static void Lockb ()
{
Lock (Obja)
{
Thread.Sleep (2000);
Lock (OBJB)
{
}
}
Console.WriteLine ("Lockb");
}


Or will Locka method also change, first lock OBJB, then lock Obja.

Of course, a brute force approach can be used, and when some threads are found to be unresponsive for a long time, they can be forcibly interrupted using the Abort method. The code is as follows:

public static void Main ()
{
Thread Threada = new Thread (Locka);
Thread threadb = new Thread (LOCKB);
Threada.start ();
Threadb.start ();

Thread.Sleep (4000);

Threada.abort ();
Threadb.abort ();
Console.WriteLine ("All Threads End");
}

Thread 4 synchronization and deadlock

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.