C # Multithreading Synchronization

Source: Internet
Author: User

There is no problem with synchronizing threads when you are writing a multi-threaded program. What is thread synchronization?

For example, if there is a variable in a company that records the salary of a person's T, there are two supervisors A and B (that is, the worker thread) who took the value of the variable back in the early days, and after a while, a supervisor adds $5 to the salary of T, and count=100 the count variable back. The B supervisor subtracts the wages of T by 3 and returns to the Count variable. Well, the original T-June can get 102 dollars of wages, now become 98 dollars. This is the problem that thread synchronization solves.

In some objects of. NET, the data can be modified while reading the data inside, and this type of object is "thread safe". However, for the code snippets that you write, you must use thread synchronization technology to ensure the integrity and correctness of the data.

There are several rules: 1, if an object (or variable) is not accessed by multiple other threads at the same time, then this object is not required to use thread synchronization. 2, if there are multiple threads accessing an object at the same time, but the data or methods they access are not the same (not cross), then this situation does not need to use thread synchronization. For example, in the example of the company where there are T and Q two people, but their salary is a and B in charge, then the processing of this wage does not need to synchronize the thread. 3. If an object is accessed by multiple other threads at the same time, it is generally only necessary to add thread-synchronized code to the object, while other threads do not need to add additional code.

There are several classes of common classes used to implement thread synchronization in C #

1. Mutex class (mutex), monitor class, lock method

2, ManualResetEvent class, AutoResetEvent class (both of which are derived from the EventWaitHandle class)

3, ReaderWriterLock Class

The same kind of role is similar: the first category of the role is to protect a piece of code executed in an exclusive manner, if there is a second thread to access this object will be paused. Wait until the exclusive code executes. Like a bunch of people at the same time a public toilet, the use of this method can be used to solve the problem at the beginning of the article: Supervisor A to deal with T-June before the salary, first lock the T-June, and then remove the current count value, after processing and then release T-June lock. If Supervisor B wants to remove the count value when he or she is dealing with a salary, it can only wait until the A has been processed before continuing. One disadvantage of using this method is that it reduces the efficiency of the program. It would have been a multiple-thread operation, and once the lock statement had been encountered, those threads would have been queued for the same single-threaded operation.

Here's an example of how these three methods are used: suppose there is an tools class, an int variable inside, and an Add and delete method, where the Add method increases the value of the int variable, and the Delete method reduces the value of the INT variable:

         Public class Tools        {            privateint;              Public void ADD (int  N)            {                + = n            ;            }  Public void Delete (int  N)            {                -= n            ;        }
View Code

When multiple threads access this code at the same time, because a statement is compiled into multiple instructions by the compiler, this can happen: But when a thread calls the Add method, the Count value is 100, and when you add N, another thread calls delete, which subtracts m, The result of Count plus N, and then in the case of the original count=100 value
Minus M, the final result is that count is subtracted from m, without adding N. It is obvious that the Add method and the Delete method cannot be called at the same time, so thread synchronization must be done. The simple approach is to use the lock statement:

         Public classTools {Private ObjectABCDE =New Object(); Private intCount = -;  Public voidADD (intN) {Lock(ABCDE) {count+=N; }            }             Public voidDelete (intN) {Lock(ABCDE) {count-=N; }            }        } 
View Code

Where ABCDE is a private class internal variable, it does not represent any meaning, just as a "token" role. When executing the lock (ABCDE) method in the Add method, the token is in the hands of the Add method, and if there is a second thread that wants to take the token, no way, just wait. Once the curly brace range of the first lock statement is finished, the seasonal card is released, and it quickly falls to the second thread, and excludes other later people.

The method of using the monitor class is roughly the same:

         Public classTools {Private ObjectABCDE =New Object(); Private intCount = -;  Public voidADD (intN) {monitor.enter (ABCDE); Count+=N;            Monitor.Exit (ABCDE); }             Public voidDelete (intN) {monitor.enter (ABCDE); Count-=N;            Monitor.Exit (ABCDE); }        }
View Code

Common methods for Monitor: Both enter and Exit are static methods, with the same effect as the two curly braces of a lock statement.
A Mutex is not required to declare a "token" object, but it can be used only after it is instantiated:

 public  class   Tools { private  Mutex mut = new   Mutex ();  private  int  count = 100   public  void  ADD (int   N) {Mut. WaitOne (); Count  +=n; Mut. ReleaseMutex ();  public  void  Delete (int   N) {Mut. WaitOne (); Count -=n; Mut. ReleaseMutex (); } } 
View Code

The WaitOne is the wait method until the mutex is released. Initially, the Mutex object is in the released state, and once the WaitOne method is executed, it is captured until it is released after the ReleaseMutex method has been called.

Using these three methods has a problem to pay attention to, that is, in the exclusive code snippet if caused by an exception, it may cause the "token" object is not released, so the program will continue to death. So the exception should be handled in the exclusive code snippet. For example, the following code is wrong:

       Public voidADD (intN) {Try{Mut.                WaitOne (); Count+=N; //.... n lines of code are omitted here//.... Here is the code that is likely to cause an exception//.... n lines of code are omitted hereMut.            ReleaseMutex (); }            Catch{Console.WriteLine ("error."); }        } 
View Code

Once the above code has an exception in the try and catch, the mutex cannot be freed, and the subsequent program will be stuck in the WaitOne () line, and should be changed to this:

        Public voidADD (intN) {Mut.            WaitOne (); Try{Count+=N; //.... n lines of code are omitted here//.... Here is the code that is likely to cause an exception//.... n lines of code are omitted here            }            Catch{Console.WriteLine ("error."); } mut.        ReleaseMutex (); } 
View Code

Now talk about the second kind: ManualResetEvent class, AutoResetEvent class

The above two classes are all derived from the EventWaitHandle class, so the functionality and invocation methods are very similar. These two classes are often used to block the execution of a thread, and then resume its execution if the condition is met. For example, you want to send flowers to a mm, give a flower to send the lad to the past, and you want to when the MM received the flowers immediately after a call to tell her.

But the problem is that you do not know when the flowers are sent to the MM hand, early to play late is not good, then you can use the ManualResetEvent object to help. When the commission

When the lad sends flowers to the past, use ManualResetEvent's WaitOne method to wait. When the lad sends the flowers to MM's hands, call again

ManualResetEvent the Set method, you will be able to call the past on time. ManualResetEvent also has a reset method, which is used to re-block the caller's execution, as if you had entrusted the lad to send flowers to n mm,

and want to be on time to call the N-mm the same situation.

usingSystem;usingSystem.Threading; Public classtestmain{Private StaticManualResetEvent ent =NewManualResetEvent (false);  Public Static voidMain () {Boy sender=NewBoy (ENT); Thread th=NewThread (NewThreadStart (sender.        Sendflower)); Th.        Start (); Ent. WaitOne (); //Waiting for workConsole.WriteLine ("I got it, I sent the flowers:)");    Console.ReadLine (); }} Public classboy{ManualResetEvent ent;  PublicBoy (ManualResetEvent e) {ent=e; }     Public voidSendflower () {Console.WriteLine ("on the way to send flowers");  for(inti =0; I <Ten; i++) {Thread.Sleep ( $); Console.Write (".."); } Console.WriteLine ("\ r \ n The flower has been sent to the MM hand, boss"); Ent. Set (); //notifies the blocking program    }}
View Code

And the AutoResetEvent class is called the meaning, is in each set after the end of the automatic reset. Let the executor re-enter the blocking state.
That is, AutoResetEvent.Set () is equivalent to Manualresetevent.set () and immediately manualresetevent.reset (),
There's nothing different about the rest.
Give an example of sending flowers to n mm:

usingSystem;usingSystem.Threading; Public classtestmain{Private StaticAutoResetEvent ent =NewAutoResetEvent (false);  Public Static voidMain () {Boy sender=NewBoy (ENT);  for(inti =0; I <3; i++) {Thread th=NewThread (NewThreadStart (sender.            Sendflower)); Th.            Start (); Ent. WaitOne (); //Waiting for workConsole.WriteLine ("I got it, I sent the flower:) \r\n\r\n");    } console.readline (); }} Public classboy{AutoResetEvent ent;  PublicBoy (AutoResetEvent e) {ent=e; }     Public voidSendflower () {Console.WriteLine ("on the way to send flowers");  for(inti =0; I <Ten; i++) {Thread.Sleep ( $); Console.Write (".."); } Console.WriteLine ("\ r \ n The flower has been sent to the MM hand, boss"); Ent. Set (); //notifies the blocker that the effect here is equivalent to ManualResetEvent's set () method +reset () method    }}
View Code

It is important to notice that both the ManualResetEvent and AutoResetEvent constructors have a bool parameter, which allows you to specify the state in which the synchronization object is blocked (set to false) or non-blocking (set to true) in the initial case.
In addition, the WaitOne method can also take two parameters:
WaitOne (int millisecondstimeout,bool exitcontext)
Millisecondstimeout: The number of milliseconds to wait, or timeout.infinite (-1), which indicates an indefinite wait.
Exitcontext: True to wait for the synchronization domain (if in the synchronization context) to exit the context before waiting, and then to retrieve it later, otherwise false.
That is, waiting can be added to a deadline, if the waiting synchronization object has been not set (), then the program will be stuck, so in the WaitOne method can be placed within a time period, the unit is milliseconds.

C # Multithreading Synchronization

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.