Lock Mechanism and atomic operation <Article 4>

Source: Internet
Author: User
I. Some Concepts in thread synchronization

1.1 concept of critical section (shared area)

In a multi-threaded environment, some public resources may need to be used together. These resources may be variables, method logic segments, and so on, these regions shared by multiple threads are collectively referred to as the critical zone. The resources in the critical zone are not very secure because the thread status is unstable, the possible result is that resources in the critical section are damaged by other threads, we must adopt policies or measures to ensure that the data in the shared area is complete in a multi-threaded environment, so that it is not damaged by multi-threaded access.

  1.2 primitive user mode

The primitive user mode refers to the use of special CPU commands to schedule threads. Therefore, this coordinated scheduling thread is implemented in hardware, so it has the following advantages:

  • Fast;
  • Thread blocking time is particularly short;

However, because the threads in this mode may be preemptible by the system, the threads in this mode will waste a lot of CPU time to obtain a certain resource. if they remain in the waiting status, they will lead to a "live lock ", that is to say, it wastes both memory and CPU time, which is more terrible than the deadlock in the following sections. How can we use the powerful CPU time to do more? The following mode is introduced.

1.3 primitive kernel mode

This mode is different from the user mode. It is provided by the Windows system and uses kernel functions in the operating system. Therefore, it can block threads and improve CPU utilization, at the same time, it also brings about a terrible bug. A deadlock may cause the program to crash due to thread blocking. Common kernel-mode technologies such as monitor, mutex, and so on. This chapter will discuss in detail the concept, usage and precautions of locks.

1.4 atomic operations

If a statement executes a separate and inseparable command, it is atomic. Strict atomic operations eliminate any possibility of preemption. It is easier to understand that this value is always the latest. in C #, the original sub-operations are shown in: in fact, to comply with atomic operations, the following conditions must be met: C #, if it is a 32-bit CPU, assign a value for a field less than or equal to 32-bit is an atomic operation, and others (auto-increment, read, write operation) is not. For a 64-bit CPU, values assigned to 32 or 64-bit fields belong to atomic operations. Other read/write operations cannot belong to atomic operations. I believe everyone can understand the characteristics of atoms, therefore, when using atomic operations, consider whether the current operating system is 32-bit or 64-bit CPU or both.

  1.5 non-blocking Synchronization

Non-blocking synchronization: synchronization is implemented without blocking other threads. It is the thread synchronization technology produced by the idea of C # non-blocking synchronization, which uses atomic operations to synchronize threads without deliberately blocking threads and reduce the overhead of the corresponding threads.

  1.6 prevent Synchronization

Blocking synchronization: blocks other threads. Only one thread can access critical resources at a time. In fact, blocking synchronization is also one of the features of the primitive kernel mode.

For example, the lock mechanism in C # And mutex and monitor all prevent synchronization. Their fundamental goal is to allow only one thread to access the shared zone at a time with mutex effect, other threads must stop waiting until the thread leaves the shared area to allow other threads to access the shared area. The disadvantage of blocking synchronization is also prone to deadlock, but blocking synchronization improves the CPU time utilization.

Ii. Why synchronization is required

When multiple threads access a resource at the same time, unexpected results may occur. For example, multiple threads can simultaneously access static resources.

Class program {static void main (string [] ARGs) {// initialize 10 threads 1 to access num for (INT I = 0; I <10; I ++) {threadpool. queueuserworkitem (New waitcallback (run);} console. readkey ();} static int num = 0; static void run (object state) {console. writeline ("current number: {0}", ++ num );}}

The output is as follows:

  

We can see that the logic of num ++ should be 1, 2, 3, 4, 5, 6, 7, 8, 9, 10. This is where multiple threads access the service in a disordered order. At this time, synchronization is required.

Iii. atomic operation synchronization Principle

The volatileread and volatilewrite methods in the Thread class:

  • Volatilewrite: When the thread transmits information in the sharing area (critical section), this method is used to write the last value atomically;
  • Volatileread: This method is used to read the first value atomically when the thread transmits information in the shared area (critical section;
Class program {static int32 count; // Count value, used for thread synchronization (pay attention to atomicity, so int32 is used in this example) Static int32 value; // actual operation value, used to display the calculation result static void main (string [] ARGs) {// read thread thread2 = new thread (New threadstart (read); thread2.start (); // write thread for (INT I = 0; I <10; I ++) {thread. sleep (20); thread = new thread (New threadstart (write); thread. start ();} console. readkey () ;}//< summary> /// actual write operation /// </Summary> Private Static void write () {int32 temp = 0; for (INT I = 0; I <10; I ++) {temp + = 1;} // truly write value + = temp; thread. volatilewrite (ref count, 1) ;}/// <summary> /// read information of the infinite loop monitoring /// </Summary> Private Static void read () {While (true) {// an endless loop listener displays the operation result if (thread. volatileread (ref count)> 0) {console. writeline ("cumulative count: {1}", thread. currentthread. managedthreadid, value); Count = 0 ;}}}}

The output is as follows:

  

Iii. Volatile keywords

The essential meaning of the volatile keyword is to tell the compiler that variables or fields declared as volatile keywords are provided to multiple threads. Volatile cannot be declared as a local variable. As an atomic operation, the volatile keyword has the atomic property, so it cannot be possessed between threads, and its value is always the latest.

Supported types of volatile:

  • Reference type;
  • Pointer type (in an insecure context );
  • Type, such as sbyte, byte, short, ushort, Int, uint, Char, float, and bool;
  • Enumeration types with one of the following basic types: byte, sbyte, short, ushort, Int, or uint;
  • Generic parameters of the reference type are known;
  • Intptr and uintptr;
Class program {static volatile int32 count; // Count value, used for thread synchronization (pay attention to atomicity, so int32 is used in this example) Static int32 value; // actual operation value, used to display the calculation result static void main (string [] ARGs) {// open up a thread specifically responsible for reading the value, in this way, we can see a computing process thread thread2 = new thread (New threadstart (read); thread2.start (); // It opens up 10 threads for computing, every thread is responsible for 10 million pieces of data for (INT I = 0; I <10; I ++) {thread. sleep (20); thread = new thread (New threadstart (write); thread. start ();} Console. readkey () ;}//< summary> /// actual write operation /// </Summary> Private Static void write () {int32 temp = 0; for (INT I = 0; I <10; I ++) {temp + = 1;} value + = temp; // tell the listener that I have changed, read the latest version! Count = 1 ;}/// <summary> /// endless loop listener /// </Summary> Private Static void read () {While (true) {If (COUNT = 1) {console. writeline ("cumulative count: {1}", thread. currentthread. managedthreadid, value); Count = 0 ;}}}}

Output:

  

Iv. Lock keywords

Lock is used to ensure that only one thread is allowed to access an object at a time.

The lock syntax is as follows:

Static object OBJ = new object (); lock (OBJ) {// statement block}

We use lock to rewrite the above example:

Class program {static void main (string [] ARGs) {// initialize 10 threads 1 to access num for (INT I = 0; I <10; I ++) {threadpool. queueuserworkitem (New waitcallback (run);} console. readkey ();} static int num = 0;Static object OBJ = newObject ();
Static void run (object state ){Lock(OBJ){Console. writeline ("current number: {0}", ++ num );}}}

The output is as follows:

  

5. Monitor. Enter and monitor. Exit

The monitor. Enter and monitor. Exit functions the same as lock. In fact. Lock is the packaging of monitor. Enter and monitor. Exit.

The following uses monitor. Enter and monitor. Exit to implement the same code:

Class program {static void main (string [] ARGs) {// initialize 10 threads 1 to access num for (INT I = 0; I <10; I ++) {threadpool. queueuserworkitem (New waitcallback (run);} console. readkey ();} static int num = 0; static object OBJ = new object (); static void run (object state) {// obtain the exclusive lock monitor. enter (OBJ); console. writeline ("current number: {0}", ++ num); // release the exclusive lock monitor. exit (OBJ );}}
6. Monitor. Wait and monitor. Pulse

The wait () and pulse () mechanisms are used for thread Interaction:

  • Wait () releases the locked resource and enters the waiting state until it is awakened;
  • The pulse () and pulseall () methods are used to notify the wait () thread to wake up;
Class program {static void main (string [] ARGs) {thread T1 = new thread (run1); thread t2 = new thread (run2); t1.start (); t1.name = "Liu Bei"; t2.start (); t2.name = "Guan Yu"; console. readkey ();} static object OBJ = new object (); static void run1 (object state) {Monitor. enter (OBJ); console. writeline (thread. currentthread. name + ": second brother, where have you been? "); Monitor. Wait (OBJ); // temporarily release the lock and let the Guan Yu thread enter console. writeline (thread. currentthread. Name +": You bastard! "); Monitor. pulse (OBJ); // wake up the Guan Yu thread monitor. exit (OBJ);} static void run2 (object state) {Monitor. enter (OBJ); console. writeline (thread. currentthread. name + ": Lao Tzu and Cao! "); Monitor. pulse (OBJ); // wake up the Liu slave thread monitor. wait (OBJ); // pause the console of this thread. writeline (thread. currentthread. name + !! "); Monitor. Exit (OBJ );}}

The output is as follows:

  

7. read/write lock readwriterlock

  Write serial, read in parallel;

If most data is read in the program, the readwriterlock class can implement "Write serial" and "read parallel" Because reading does not affect data.

The common method is as follows:

  • Acquirewriterlock: Get the write lock; releasewriterlock: Release the write lock.
  • Acquirereaderlock: Get the read lock; releasereaderlock: Release the read lock.
  • Upgradetowriterlock: converts a read lock into a write lock; downgradefromwriterlock: Restores a write lock to a read lock.
Class program {static list <string> liststr = new list <string> (); static readerwriterlock RW = new system. threading. readerwriterlock (); static void main (string [] ARGs) {thread T1 = new thread (run1); thread t2 = new thread (run2); t1.start (); t1.name = "Liu Bei"; t2.start (); t2.name = "Guan Yu"; console. readkey ();} static object OBJ = new object (); static void run1 (object state) {// get the write lock for 2 seconds RW. acquirewriterlo CK (2000); console. writeline (thread. currentthread. Name + "is being written! "); Liststr. add ("Cao asshole"); liststr. add ("sunquan bastard"); thread. sleep (1200); liststr. add ("Tom Zhou"); RW. releasewriterlock () ;}// this method is abnormal and times out because the write operation is not allowed to read (so you can guess it is not allowed to write) Static void run2 (object state) {// obtain the read lock for 1 second RW. acquirereaderlocks (1000); console. writeline (thread. currentthread. name + "reading! "); Foreach (string STR in liststr) {console. writeline (STR);} RW. releasereaderlock ();}}

The exception is as follows:

  

The following is an example of parallel reading:

Class program {static list <string> liststr = new list <string> (); static readerwriterlock RW = new system. threading. readerwriterlock (); static void main (string [] ARGs) {liststr. add ("mink"); liststr. add ("Xi Shi"); liststr. add ("Wang Zhaojun"); thread T1 = new thread (run1); thread t2 = new thread (run2); t1.start (); t1.name = "Liu Bei"; t2.start (); t2.name = "Guan Yu"; console. readkey ();} static object OBJ = new object (); ST Atic void run1 (object state) {// get the write lock for 2 seconds RW. acquirereaderlock (2000); console. writeline (thread. currentthread. Name + "reading! "); Foreach (string STR in liststr) {console. writeline (thread. currentthread. name + "reading:" + Str);} RW. releasereaderlock ();} // This method is abnormal and times out because it is not allowed to be read during writing (so you can guess that it is not allowed to write) Static void run2 (object state) {// obtain the read lock for 1 second RW. acquirereaderlocks (1000); console. writeline (thread. currentthread. name + "reading! "); Foreach (string STR in liststr) {console. writeline (thread. currentthread. Name +" reading: "+ Str) ;}rw. releasereaderlock ();}}

The output is as follows:

  

Conclusion: The write lock is incompatible with any lock, and the read lock is compatible with the read lock.

Lock Mechanism and atomic operation <Article 4>

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.