The lock keyword can be used to ensure that a block of code finishes running without being interrupted by another thread. It can define a piece of code as a mutex (critical section), where the mutex only allows one thread to go into execution at a time, while other threads must wait. This is achieved by obtaining a mutex for a given object during the code block run.
In multi-threading, each thread has its own resources, but the code area is shared, that is, each thread can execute the same function. The problem is that several threads execute a function at the same time, causing the data to clutter and produce unpredictable results, so we have to avoid this happening.
And in. NET is best to understand the concepts of processes, application domains, and threads, because lock is for thread-level, and in. NET, my guess is that threads that are not in the same application domain cannot be interrupted by lock, and it is also better to understand the concepts of data segments, code snippets, heaps, stacks, and so on.
The C # lock keyword is defined as follows:
Lock (expression) Statement_block, where expression represents the object you want to track, typically an object reference.
If you want to protect an instance of a class, generally, you can use this; if you want to protect a static variable (such as a mutex snippet inside a static method), you can use the class name generally.
And Statement_block is the code of the mutex, which can only be executed by one thread at a time.
Second, a simple example
Using System;
Using System.Collections;
Using System.Collections.Generic;
Using System.Threading;
Namespace ConsoleApplication1
{
Class Program
{
static void Main (string[] args)
{
Thread thread1 = new Thread (new ThreadStart (ThreadStart1));
Thread1. Name = "Thread1";
Thread thread2 = new Thread (new ThreadStart (THREADSTART2));
Thread2. Name = "Thread2";
Thread thread3 = new Thread (new ThreadStart (THREADSTART3));
Thread3. Name = "Thread3";
Thread1. Start ();
Thread2. Start ();
Thread3. Start ();
Console.readkey ();
}
Static Object _object = new Object ();
static void done (int millisecondstimeout)
{
Console.WriteLine (String. Format ("{0}", {1}. Start ", DateTime.Now.ToString (" HH:mm:ss "), Thread.CurrentThread.Name));
The code snippet below can only be executed by one thread at a time
Lock (_object)
{
Console.WriteLine (String. Format ("{0}, {1} enters the locked area.", DateTime.Now.ToString ("HH:mm:ss"), Thread.CurrentThread.Name));
Thread.Sleep (millisecondstimeout);
Console.WriteLine (String. Format ("{0}, {1} exits the locked area.", DateTime.Now.ToString ("HH:mm:ss"), Thread.CurrentThread.Name));
}
}
static void ThreadStart1 ()
{
Done (5000);
}
static void ThreadStart2 ()
{
Done (3000);
}
static void ThreadStart2 ()
{
Done (1000);
}
}
}
Three, briefly explain the implementation process
Let's take a look at the execution process, with the following code examples:
private static Object OJB = new Object ();
Lock (obj)
{
Lock a running code snippet
}
Assuming that thread a executes first, thread B is slightly slower. Thread A executes to the lock statement and determines if obj has applied for the mutex, judging by the existence of an object on a per-existing lock. ReferenceEquals comparison (not shown here), if it does not exist, then request a new mutex, then thread a enters lock.
This assumes that thread B is started, and thread A has not finished executing the code inside lock. Thread B executes to the lock statement, checks that obj has applied for the mutex, waits until thread a finishes executing, releases the mutex, and thread B can request a new mutex and execute the code inside the lock.
Four, Lock's object selection problem
Next, say something about what lock should be locked.
1. Why can't lock value type
Like lock (1)? Lock essentially monitor.enter,monitor.enter the value type, each time the lock is a boxed object. Lock is actually a compiler-like syntax sugar, so the compiler directly restricts the lock value type. Step back 10,000 to say, even if the compiler allows you to lock (1), but object. ReferenceEquals always returns False (since each boxing is a different object), that is, each time it is judged not to request a mutex, so that at the same time, other threads can still access the inside of the code, does not achieve the effect of synchronization. Likewise, lock (object) 1 is not.
2. Lock string
What about the lock ("xxx") string? The exact words on MSDN are:
Locking a string is especially risky because the string is persisted by the common language runtime (CLR). This means that there is only one instance of any given string in the entire program, which is the same object that represents the text in all the threads of all running application domains. Therefore, whenever a lock is placed on a string that has the same content anywhere in the application process, all instances of that string in the application are locked.
3. MSDN Recommended Lock Object
In general, it is a good idea to avoid locking public types or locking object instances that are not under application control. For example, if the instance can be publicly accessible, lock (this) may be problematic because uncontrolled code may also lock the object. This can result in a deadlock, where two or more threads wait to release the same object. For the same reason, locking public data types (compared to objects) can also cause problems.
and lock (this) is only valid for the current object, if the synchronization effect is not achieved between multiple objects.
The custom class recommends using private read-only static objects, such as:
private static readonly Object obj = new Object ();
Why should it be set to read-only? This is because if you change the value of obj in the lock code snippet, the other threads are unblocked because the mutex object has changed. ReferenceEquals must return FALSE.
4. Lock (typeof (Class))
As with the lock string, the range is too wide.
V. Special questions: Detailed explanations of Lock (this), etc.
In the previous programming encountered lock problem always use lock (this) one locked, after the problem looked at MSDN suddenly found the following line of words: Generally, you should avoid locking the public type, otherwise the instance will go beyond the control of the code. Common structure Lock (this), Lock (typeof (MyType)), and Lock ("MyLock") violate this guideline: if the instance can be accessed publicly, the C # lock this issue occurs. If MyType can be accessed publicly, a lock (typeof (MyType)) issue will occur. The Lock ("MyLock") issue occurs because any other code that uses the same string in a process will share the same lock.
Take a look at the C # lock This problem: if there is a class Class1, the class has a method with lock (this) to implement the mutex:
- PUBLICVOIDMETHOD2 ()
- {
- Lock (This)
- {
- System.Windows.Forms.MessageBox.Show ("Method2end");
- }
- }
If in the same Class1 instance, the METHOD2 can be mutually exclusive execution. However, if the instance of 2 Class1 is executed Method2, there is no mutex effect. Because of the lock here, only the current instance object is locking.
Lock (typeof (MyType)) has a wider range of locked objects, because all instances of a class have only one type object (the object is the return result of the TypeOf), locking it, locks all instances of the object, and Microsoft now recommends that you do not use Lock (typeof ( MyType), because locking type objects is a slow process, and other threads in the class, even other programs running in the same application domain, can access that type of object, so they are likely to be used instead of locking your type object, completely blocking your execution, causing your own code to hang.
Locking a string is more magical, as long as the string content is the same, it can cause the program to hang. The reason is that. NET, the string is temporarily stored, if the string contents of the two variables are the same. NET assigns a staged string object to the variable. So if you have two places with lock ("my lock"), they actually lock the same object. Here, Microsoft gives a lock's suggested usage: lock a private static member variable.
. NET in some collection classes (such as Arraylist,hashtable,queue,stack) has provided a lock for the use of the object SyncRoot, with the reflector tool to view the SyncRoot properties of the code, in the array, This property has only one sentence: return this, which is the same as the current instance of the lock array. The SyncRoot in ArrayList are different
- Get
- {
- if (this._syncroot==null)
- {
- Interlocked.compareexchange (Refthis._syncroot,newobject (), NULL);
- }
- Returnthis._syncroot;
Where the Interlocked class is an atomic operation specifically for variables shared by multiple threads (if the object you want to lock is the base data type, use this class), the CompareExchange method compares the current syncroot to NULL, and if it is equal, replace it with the new Object (), which is done to ensure that multiple threads are thread-safe when using SyncRoot. Another method in the collection class is related to synchronization: Synchronized, which returns the wrapper class of the corresponding collection class, which is thread-safe because most of his methods are synchronized with lock, such as the Add Method:
- Publicoverridevoidadd (Objectkey,objectvalue)
- {
- Lock (this._table. SyncRoot)
- {
- This._table. ADD (Key,value);
- }
- }
It is important to note that MSDN mentions that enumerating a collection from beginning to end is not inherently a thread-safe process. Even if a collection is synchronized, other threads can still modify the collection, which causes the enumerator to throw an exception. To ensure thread safety during enumeration, you can lock the collection throughout the enumeration process:
- Queuemycollection=newqueue ();
- Lock (Mycollection.syncroot) {
- foreach (objectiteminmycollection) {
- Insertyourcodehere.
- }
- }
At last
Note: You should avoid locking the public type, or the instance will go beyond the control of your code. Common structure Lock (this), Lock (typeof (MyType)) and lock ("MyLock") violate this guideline:
1) If the instance can be accessed publicly, the lock (this) problem will occur;
2) If MyType can be accessed publicly, the lock (typeof (MyType)) issue will occur;
3) A lock ("myLock") issue occurs because any other code that uses the same string in the process will share the same lock;
The best practice is to define private objects to lock, or private static object variables to protect data that is common to all instances.
Vi. references
Since the reference information is stored locally, only the title can be listed first, unable to provide the original address, sorry!
1) describes the C # multi-threaded lock keyword
2) solve the C # lock this issue
3) Summary of the lock keyword based on C #
4) C # lock keyword
Original:http://www.cnblogs.com/zhanglb/archive/2012/01/02/2310420.html
C # Lock Interpretation [Go]