[C # thread processing series] Topic 4: Thread Synchronization

Source: Internet
Author: User

 

Directory:

I. Thread Synchronization Overview

Ii. Use of Thread Synchronization

Iii. Summary

 

I. Thread Synchronization Overview

 

PreviousArticleIt is about creating multiple threads to achieve better response to applications.ProgramHowever, when we create multiple threads, multiple threads can simultaneously access a shared resource. In this case, we need to use thread synchronization, thread Synchronization Can Prevent data (shared resources) corruption.

However, when designing applications, we should try to avoid using thread synchronization, because thread synchronization may cause some problems:

1. It is cumbersome to use. Because we need to use additionalCodeEnclose data accessed by multiple threads at the same time and obtain and release a thread synchronization lock. If we forget to obtain the lock in a code block, it may cause data corruption.

2. using thread synchronization affects performance. It takes some time to obtain and release a lock, because the CPU must be coordinated when determining which thread gets the lock first, this extra work will affect the performance.

3. because a thread only allows one thread to access resources at a time, it will block the thread, blocking the thread will cause more threads to be created, so that the CPU may need to schedule more threads, it also has an impact on performance.

In actual design, we should avoid using thread synchronization as much as possible. Therefore, we should avoid using shared data, such as static fields.

 

Ii. Use of Thread Synchronization

 

2.1 Impact on lock performance

As mentioned above, the use of locks will affect the performance. The following describes the use of locks and the time consumed when no locks are used.

 Using  System;  Using  System. diagnostics;  Using  System. Threading;  Namespace Interlockedsample {  //  Compare the time consumed by using locks and not using locks  //  Time is used to describe the impact of lock performance      Class  Program {  Static   Void Main ( String  [] ARGs ){  Int X = 0  ;  // Iterations: 5 million              Const   Int Iterationnumber = 5000000  ;  //  No lock is used.  //  The startnew method initializes the new stopwatch instance, sets the runtime attribute to zero, and starts measuring the runtime. Stopwatch Sw = Stopwatch. startnew ();  For ( Int I = 0 ; I <iterationnumber; I ++) {X ++ ;} Console. writeline (  "  Use the all time is: {0} MS  "  , SW. elapsedmilliseconds); Sw. Restart ();  //  Lock usage              For ( Int I = 0 ; I <iterationnumber; I ++ ) {Interlocked. increment (  Ref X);} console. writeline (  "  Use the all time is: {0} MS  "  , SW. elapsedmilliseconds); console. Read ();}}} 

Running results (this is the result of running on my computer) from the results, we can see that the locking operation is much slower (11 times slower than 197/18 ):

 

2.2 interlocked implement Thread Synchronization

The interlocked class providesAtomic operations are provided for variables shared by multiple threads. When we increment an integer in multiple threads, thread synchronization is required.

BecauseThe add variable operation (++ operator) is not an atomic operation. perform the following steps:

1) load the values in instance variables into registers.

2) increase or decrease the value.

3) store the value in the instance variable.

If you do not useInterlocked. IncrementThe thread may be preemptible after the first two steps are executed. Then, the other thread executes all three steps. At this time, the first thread has not stored the variable value in the instance variable, the other thread can load the instance variables into the registers and read them (the loaded values are not changed at this time), so the results may not be as expected, I believe this explanation can help you better understand it.Interlocked. IncrementMethods and atomic operations,

The following code demonstrates the difference between locking and non-locking. (I started to talk about the impact of locking on performance. Here we will introduce locking to solve the thread synchronization problem and get our expected results):

No lock:

Class  Program {  Static   Void Main ( String  [] ARGs ){  For ( Int I = 0 ; I < 10 ; I ++ ) {Thread testthread = New Thread (ADD); testthread. Start ();} console. Read ();}  //  Shared resources          Public   Static   Int Number = 1  ;  Public   Static   Void  Add () {thread. Sleep (10  00  ); Console. writeline ( "  The current value of number is: {0}  " , ++ Number );}} 

Running results (the results on different computers may be different from mine, but they all get unexpected results ):

To solve this problem, we can useInterlocked. IncrementMethod to implement the atomic auto-increment operation.

The code is very simple. You only need to change ++ number to interlocked. increment (RefNumber) to get the expected results. Here the code and running results are not pasted.

In shortInterlockedAll methods in the class perform an atomic read and write operation.

 

2.3 Monitor thread synchronization

ForYou can also useThe monitor. Enter and monitor. Exit methods are used to synchronize threads. In C #, the lock keyword is used to provide simplified syntax (lock can be understood as the syntax sugar of the monitor. Enter and monitor. Exit methods). The Code is also very simple:

 

 Using  System;  Using  System. Threading;  Namespace  Monitorsample {  Class  Program {  Static   Void Main ( String [] ARGs ){  For ( Int I = 0 ; I < 10 ; I ++ ) {Thread testthread = New  Thread (ADD); testthread. Start ();} console. Read ();}  //  Shared resources          Public   Static   Int Number =1  ;  Public   Static   Void  Add () {thread. Sleep (  1000  );  //  Obtain exclusive lock  Monitor. Enter (number); console. writeline (  "  The current value of number is: {0}  " , Number ++ ); //  Releases the exclusive lock on the specified object.  Monitor. Exit (number );}}} 

Of course, the running result is what we expect:

There are several other methods in the monitor class, which are also introduced here. It is just worth noting that the role of a wait method is obvious:Release the lock on an object to allow other threads to lock and access this object. The second isTryenter method. The main difference between this method and the enter method is whether to block the current thread. When an object acquires the lock through the enter method, the exit method is not executed to release the lock, when another thread wants to get the lock through enter, the thread will be blocked until another thread releases the lock, and tryenter will not block the thread. The specific code will not be written.

 

2.4 readerwriterlock for Thread Synchronization

If we need to execute multiple reads to a shared resource, but the synchronization lock implemented by the class mentioned above only allows one thread, all threads will be blocked, however, in this case, there is no need to block other threads, So we should let them execute concurrently, because we only need to perform read operations at this time. At this time, the readerwriterlock class can effectively implement read concurrency.

The Demo code is:

 

 Using  System;  Using  System. Collections. Generic;  Using  System. Threading;  Namespace  Readerwriterlocksample {  Class  Program {  Public  Static List < Int > Lists = New List < Int > ();  //  Create an object          Public   Static Readerwriterlock readerwritelock = New  Readerwriterlock ();  Static   Void Main ( String [] ARGs ){  //  Create a thread to read data Thread T1 = New  Thread (write); t1.start ();  //  Create 10 threads to read data              For ( Int I = 0 ; I < 10 ; I ++ ) {Thread t = New Thread (read); T. Start ();} console. Read ();}  //  Write Method          Public   Static   Void  Write (){  //  Get the write lock, timeout in 10 milliseconds. Readerwritelock. acquirewriterlock ( 10  ); Random ran = New  Random (); Int Count = ran. Next ( 1 , 10  ); Lists. Add (count); console. writeline (  "  Write the data is:  " + Count );  //  Release write lock  Readerwritelock. releasewriterlock ();}  //  Read Method          Public  Static   Void  Read (){  //  Get read lock Readerwritelock. acquirereaderlock ( 10  );  Foreach ( Int Li In  Lists ){  //  Output read data  Console. writeline (LI );} //  Release read lock  Readerwritelock. releasereaderlock ();}}} 

Running result:

Iii. Summary

This article mainly introduces how to implement multi-thread synchronization. Thread Synchronization Can Prevent Corruption of shared data, but the performance loss may occur due to the lock acquisition process, therefore, the use of thread synchronization should be minimized during application design. I would like to introduceMutex (mutex), semaphore (semaphore), event construction. Due to space reasons, it may affect reading, so the rest of the content will be described later. 

 

 

Related Article

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.