C lock in detail

  • 2020-11-25 07:29:22
  • OfStack

This article illustrates the use of lock in C#. Share to everybody for everybody reference. The specific analysis is as follows:

The lock keyword can be used to ensure that blocks of code complete the run without being interrupted by other threads. This is done by obtaining a mutex for a given object while the block of code is running.

Let's take a look at the execution process, with the following code example:

The lock statement is used to get a mutex for a given object, execute 1 statement, and then release the lock.
lock-statement:(lock)

lock(expression) embedded-statement(lock   (    expression    )    The embedded statement )

The expression of the lock statement must represent the value of 1 reference type. Implicit boxing conversions are never performed for expressions in lock statements, so if the expression represents a value of a value type, it will result in a compile-time error.

lock statements in the following form:

lock (x) ...

Where x is an expression of 1 reference type) is completely equivalent to
system.threading.monitor.enter(x);
try {
   ...
}
finally {
   system.threading.monitor.exit(x);
}

The difference is that in practice x is calculated only once.
When a mutex is occupied, code executing in the same thread can still acquire and release the lock. However, code executed in other threads will not be able to acquire the lock until it is released.

An system. type object of 1 class can be easily used as a mutex for static methods of that class. Such as:

class cache
{
   public static void add(object x) {
      lock (typeof(cache)) {
         ...
      }
   }
   public static void remove(object x) {
      lock (typeof(cache)) {
         ...
      }
   }
}

Suppose thread a executes first and thread b is a little bit slower. Thread a executes the statement of lock to determine whether obj has applied for a mutex by comparing object.referenceequals one by one with the existing locks (not verified here). If it does not exist, it applies for a new mutex, and then thread a enters into lock.
At this point, assume that thread b has started and thread a has not yet finished executing the code in lock. Thread b executes the lock statement, checks that obj has applied for a mutex, and waits. Until thread a finishes executing and releases the mutex, thread b cannot apply for a new mutex and execute the code in lock.

Next, say something about the lock object.

Why not lock value types, such as lock(1) ? lock monitor.enter, monitor.enter essentially boxed the value type, each time lock's object is boxed. lock is actually a compiler like syntax sugar, so the compiler directly restricts the lock value type.

Back 10,000 steps, even if the compiler allows you to lock(1), object.referenceequals (1,1) will always return false(because each box is a different object), that is, each time will be determined that the mutex is not applied, so at the same time, other threads can still access the code inside, do not achieve the effect of synchronization. The same cannot be said for lock((object)1).

What about the lock("xxx") string ? The words on msdn are:

Locking strings are particularly dangerous because strings are "held" by the common Language runtime (clr). This means that there are only 1 instance of any given string in the entire program, that is, this same object represents the text in all threads of all running application domains. Therefore, any time a lock is placed on a string with the same content anywhere in the application process, all instances of that string in the application will be locked.

In general, it is best to avoid locking public types or object instances that are not under the control of your application. For example, lock(this) may be problematic if the instance is publicly accessible, because uncontrolled code can also lock the object. This can result in a deadlock, where two or more threads are waiting to release the same object. For the same reason, locking common data types (as opposed to objects) can also cause problems. And lock(this) only works on the current object if multiple objects cannot be synchronized.

lock(typeof(class)) looks like the lock string 1 and is too wide in scope.

Some system classes provide members specifically for locking. For example, the array type provides syncroot. Many collection types also provide syncroot.

Custom classes recommend using private read-only static objects, such as:

private static readonly object obj = new object();

Why do you want to make it read-only? This is because if you change the value of obj in the lock code block, other threads are free because of the mutex
Object changed, object. referenceequals must return false.

Hopefully this article has helped you with your C# programming.


Related articles: