C # thread lock (up)

Source: Internet
Author: User
Tags mscorlib
This article starts with the class relationship diagram of Monitor, Mutex, ManualResetEvent, AutoResetEvent, and WaitHandler. I hope that through this introduction, I can have a general understanding of common thread synchronization methods, the application details of each method are not explained too much. Let's take a look at the relationships between these classes:

 

1. lock keyword

Lock is the C # keyword. It marks the statement block as a critical section to ensure that when one thread is located in the critical section of the Code, the other thread does not enter the critical section. If other threads attempt to enter the locked code, it waits until the object is released. The method is to obtain the mutex lock of a given object, execute the statement, and then release the lock.

MSDN provides considerations for using lock. Generally, you should avoid locking the public type. Otherwise, the instance will be out of the control scope of the Code. Common structures such as lock (this), lock (typeof (MyType), and lock ("myLock") violate this rule.

1) if the instance can be accessed by the public, the lock (this) problem will occur.

2) If MyType can be publicly accessed, the lock (typeof (MyType) problem will occur. Because all instances of a class have only one type object (this object is the return result of typeof ), lock it to lock all instances of the object. At present, Microsoft does not recommend using lock (typeof (MyType) because locking type objects is a very slow process, other threads in the class, or even other programs running in the same application domain, can access this type of object. Therefore, they may be used to lock the type object instead of you, it completely blocks your execution and causes your own code to be suspended.

3) any other code using the same string in the process will share the same lock, so the lock ("myLock") problem occurs. This problem is related to the mechanism by which. NET Framework creates strings. If both string values are "myLock", the memory points to the same string object.

The best practice is to define private objects to lock, or private static object variables to protect the data shared by all instances.

Let's take a look at the essence of the lock keyword through IL Dasm. Below is a simple test code:

Lock (lockobject)
{
Int I = 5;
}

Use IL Dasm to open the compiled file. The above statement block generates the IL code:

IL_0045: call void [mscorlib] System. Threading. Monitor: Enter (object)
IL_004a: nop
. Try
{
IL_004b: nop
IL_004c: ldc. i4.5
IL_004d: stloc.1
IL_004e: nop
IL_004f: leave. s IL_0059
} // End. try
Finally
{
IL_0051: ldloc.3
IL_0052: call void [mscorlib] System. Threading. Monitor: Exit (object)
IL_0057: nop
IL_0058: endfinally
} // End handler

Through the above code, we can clearly see that the lock keyword is actually an encapsulation of the Enter () and Exit () Methods of the Monitor class, and through try... catch... the finally statement block ensures that Monitor is executed after the lock statement block ends. exit () method to release the mutex lock.

2. Monitor class

The Monitor class grants an object lock to a single thread to control access to the object. Object locks provide the ability to restrict access to critical zones. When a thread has an object lock, no other thread can obtain the lock. You can also use Monitor to ensure that no other thread is allowed to access the application code section being executed by the lock owner, unless another thread is using another lock object to execute the code.

Through the analysis of the lock keyword, we know that lock is an encapsulation of the Enter and Exit of Monitor, and it is more concise to use. Therefore, the Enter () and Exit () of the Monitor class () the combination of methods can be replaced by the lock keyword.

In addition, the Monitor class has several common methods:

TryEnter () can effectively solve problems such as long-term crashes. If TryEnter is used frequently in a concurrent and persistent environment, it can effectively prevent deadlocks or long waits. For example, you can set a waiting time bool gotLock = Monitor. TryEnter (myobject, 1000) so that the current thread can decide whether to continue the following operations based on the returned bool value after waiting for 1000 seconds.

Wait () releases the lock on the object to allow other threads to lock and access the object. When other threads access an object, the calling thread will wait. The pulse signal is used to notify the waiting thread of changes to the object state.

Pulse (), PulseAll () sends signals to one or more waiting threads. This signal indicates that the status of the waiting thread lock object has changed, and the lock owner is ready to release the lock. Wait for the thread to be placed in the ready queue of the object so that it can finally receive the object lock. Once the thread has a lock, it can check the new State of the object to see if it has reached the desired state.

Note: The Pulse, PulseAll, and Wait methods must be called from the synchronized code block.

Let's assume a situation: Mom makes a cake, and the child is a little embarrassed. Mom needs to eat every piece of cake she prepared. After the mother prepared a piece, she told the child that the cake was ready. The following example uses the Wait and Pulse methods of the Monitor class to simulate a child's eating cake.

Example of Wait and Pulse
// Only an example of Wait and Pulse/PulseAll
// The logic is not strict, and the application scenario is not necessarily suitable.
Class MonitorSample
{
Private int n = 1; // data jointly processed by the producer and consumer
Private int max = 10000;

Private object monitor = new object ();

Public void Produce ()
{
Lock (monitor)
{
For (; n <= max; n ++)
{
Console. WriteLine ("Mom: Day" + n. ToString () + "cake ready ");
// The Pulse method does not need to be called because the other thread uses the Wait (object, int) method.
// This method causes the blocked thread to enter the ready queue of the synchronization object.
// Whether Pulse activation is required is an important difference between one parameter and two parameters in the Wait Method
// Monitor. Pulse (monitor );
// Call the Wait method to release the lock on the object and stop the thread (the thread state is WaitSleepJoin)
// This thread enters the waiting queue of the synchronization object until other threads call Pulse to make the thread enter the ready queue.
// The thread enters the ready queue to compete for the ownership of the synchronization object.
// If no other thread calls the Pulse/PulseAll method, this thread cannot be executed
Monitor. Wait (monitor );
}
}
}

Public void Consume ()
{
Lock (monitor)
{
While (true)
{
// Notifies the thread in the waiting queue of changing the status of the locked object, but does not release the lock.
// After receiving the Pulse, the thread moves from the waiting queue of the synchronization object to the ready queue.
// Note: the thread that can finally obtain the lock is not necessarily the thread that gets the Pulse.
Monitor. Pulse (monitor );
// Release the lock on the object and stop the current thread until it gets the lock again
// If the specified Timeout interval has passed, the thread enters the ready queue.
Monitor. Wait (monitor, 1000 );
Console. WriteLine ("Child: start to eat" + n. ToString () + "cake ");
}
}
}

Static void Main (string [] args)
{
MonitorSample obj = new MonitorSample ();
Thread tProduce = new Thread (new ThreadStart (obj. Produce ));
Thread tConsume = new Thread (new ThreadStart (obj. Consume ));
// Start threads.
TProduce. Start ();
TConsume. Start ();

Console. ReadLine ();
}
}

The purpose of this example is to understand how Wait and Pulse ensure thread synchronization, and pay attention to the differences between Wait (obeject) and Wait (object, int) methods, the key to understanding the differences between them is to understand that the synchronization object contains several references, including references to the thread with the current lock and the ready queue (including the thread preparing to obtain the lock) and the reference to the waiting queue (including the threads waiting for the notification of object status changes.

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.