C # Multithread synchronization,

Source: Internet
Author: User

C # Multithread synchronization,

Thread Synchronization is inevitable when writing multi-threaded programs. What is thread synchronization?

For example, if A company has A variable that records the salary count of someone T = 100, there are two supervisors A and B (that is, the working thread) in the early days, I took the value of this variable back. After A while, supervisor A added 5 T's salary and returned the count variable, the B supervisor deducts T's salary by 3 and returns the count variable. Well, T Jun was able to get 102 yuan of salary, and now it's 98 yuan. This is the problem to be solved during thread synchronization.

Some objects in. Net can also modify data while reading data. Such objects are "thread-safe ". However, for self-compiled code segments, thread synchronization technology must be used to ensure data integrity and correctness.

There are several rules: 1. If an object (or variable) is not simultaneously accessed by multiple other threads, this object does not need to be synchronized by threads. 2. If multiple threads access an object at the same time, but the data or methods they access are not the same (not cross), then thread synchronization is not required. For example, if the company in the above example has T and Q two people, but their salaries are respectively led by A and B, then the processing of this salary does not require thread synchronization. 3. If an object is accessed by multiple other threads at the same time, you only need to add the code for thread synchronization to this object, but other threads do not need to add additional code.

Common classes used in C # To implement thread synchronization are as follows:

1. Mutex class (Mutex), Monitor class, and lock Method

2. ManualResetEvent class and AutoResetEvent class (both are derived from the EventWaitHandle class)

3. ReaderWriterLock class

The role of the same class is similar: the role of the first class is to protect a piece of code from being executed in an exclusive manner, in this case, if the second thread wants to access this object, it will be paused. Wait until the exclusive code is executed. Just like A bunch of people put on A public toilet at the same time, this method can solve the problem raised at the beginning of the article: Supervisor A should lock T Jun before dealing with T Jun's salary, then the current count value is taken out, and T Jun's lock is removed after processing. If supervisor B wants to retrieve the count value when supervisor A processes the salary, it can only continue after supervisor A finishes processing the salary. One disadvantage of using this method is that it will reduce program efficiency. It is an operation of multiple threads. Once a lock statement is encountered, these threads only need to queue for processing and form the same single-thread operation.

The following example shows how to use these three methods: assume there is a Tools class, which contains an int variable and the Add and Delete methods. The Add method will increase the value of the int variable, the Delete method reduces the int variable value:

Public class Tools {private int count = 100; public void Add (int n) {count + = n;} public void Delete (int n) {count-= n ;}}View Code

When multiple threads access this code at the same time, this may occur because a statement is compiled into multiple commands by the compiler: but when a thread calls the Add method, at this time, the count value is 100. When n is to be added, another thread calls Delete. m is subtracted, and n is added to the result count, then, in the original count = 100 value
After m is removed, the final result is that m is subtracted from count without n. Obviously, the Add and Delete methods cannot be called at the same time, So thread synchronization is required. A simple method is to use the lock statement:

Public class Tools {private object abcde = new object (); private int count = 100; public void Add (int n) {lock (abcde) {count + = n ;}} public void Delete (int n) {lock (abcde) {count-= n ;}}}View Code

Among them, abcde is a private internal variable, which does not represent any meaning, but serves as a "token" role. When the lock (abcde) method in the Add method is executed, this token is in the hands of the Add method. If there is a second thread that wants to take this token, there is no way, only waiting. Once the bracket range of the first lock statement ends, the token is released and quickly falls into the hands of the second thread, and other later users are excluded.

The methods for using the Monitor class are roughly the same:

Public class Tools {private object abcde = new object (); private int count = 100; public void Add (int n) {Monitor. enter (abcde); count + = n; Monitor. exit (abcde);} public void Delete (int n) {Monitor. enter (abcde); count-= n; Monitor. exit (abcde );}}View Code

Common Methods of Monitor: both Enter and Exit are static methods, which are used in the same way as the two curly braces of the lock statement.
Instead of declaring a "token" object, Mutex can be used only after being 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

WaitOne is the waiting method and waits until Mutex is released. Initially, the Mutex object is in the release state. Once the WaitOne method is executed, it is captured and released until the ReleaseMutex method is called.

There is a need to pay attention to using these three methods, that is, if an exception occurs in the exclusive code segment, the "token" object may not be released, in this way, the program will continue to die. Therefore, you must handle exceptions in the exclusive code segment. For example, the following code is incorrect:

Public void Add (int n) {try {mut. waitOne (); count + = n ;//.... N lines of code are omitted here //.... here is the code that may cause exceptions //.... N lines of code mut are omitted here. releaseMutex ();} catch {Console. writeline ("error. ");}}View Code

Once an exception occurs in the above Code in try and catch, the Mutex cannot be released, and the subsequent program will be stuck in the WaitOne () line, but should be changed to this:

Public void Add (int n) {mut. waitOne (); try {count + = n ;//.... N lines of code are omitted here //.... here is the code that may cause exceptions //.... N lines of code are omitted here} catch {Console. writeline ("error. ");} mut. releaseMutex ();}View Code

Now let's talk about the second: ManualResetEvent class, AutoResetEvent class

The above two classes are derived from the EventWaitHandle class, so the functions and call methods are very similar. These two classes are often used to block the execution of a thread and resume execution when the conditions are met. For example, if you want to send flowers to a MM and ask a young man to send flowers, you want to call her immediately after receiving the flowers.

But the problem is that you don't know when it will be delivered to MM, and it's not good if it's late. At this time, you can use the ManualResetEvent object for help. Commission

When the young man sent flowers, he used the WaitOne method of ManualResetEvent to wait. When the young man sends the flowers to MM, he can call it again.

You can call the Set Method of ManualResetEvent on time. In addition, ManualResetEvent also has a Reset method to re-block the caller's execution. In this case, you entrust this guy to send flowers to n mm,

The same is true if you want to call the n mm on time.

Using System; using System. threading; public class TestMain {private static ManualResetEvent ent = new ManualResetEvent (false); public static void Main () {Boy sender = new Boy (ent ); thread th = new Thread (new ThreadStart (sender. sendFlower); th. start (); ent. waitOne (); // wait for the work Console. writeLine ("I have received it. I sent the response for the flowers :)"); Console. readLine () ;}} public class Boy {ManualResetEvent ent; public Boy (ManualResetEvent e) {ent = e;} public void SendFlower () {Console. writeLine ("On the Way to sending flowers"); for (int I = 0; I <10; I ++) {Thread. sleep (1, 200); Console. write (".. ");} Console. writeLine ("\ r \ n flowers have been delivered to MM, boss"); ent. set (); // notification blocking program }}View Code

The AutoResetEvent class automatically Reset after each Set. Let the program re-enter the blocking status.
That is, AutoResetEvent. Set () is equivalent to ManualResetEvent. Set () and then immediately ManualResetEvent. Reset (),
Nothing else is different.
Here is an example of sending flowers to n mm:

Using System; using System. threading; public class TestMain {private static AutoResetEvent ent = new AutoResetEvent (false); public static void Main () {Boy sender = new Boy (ent); for (int I = 0; I <3; I ++) {Thread th = new Thread (new ThreadStart (sender. sendFlower); th. start (); ent. waitOne (); // wait for the work Console. writeLine ("have you received it, I sent the token :) \ r \ n");} Console. readLine () ;}} public class Boy {AutoResetEvent ent; public Boy (AutoResetEvent e) {ent = e;} public void SendFlower () {Console. writeLine ("On the Way to sending flowers"); for (int I = 0; I <10; I ++) {Thread. sleep (1, 200); Console. write (".. ");} Console. writeLine ("\ r \ n flowers have been delivered to MM, boss"); ent. set (); // notification blocking program. The effect here is equivalent to the Set () method + Reset () method of ManualResetEvent }}View Code

Note that both ManualResetEvent and AutoResetEvent constructor have a bool parameter. You can use this parameter to specify that the synchronization object is blocked in the initial condition (set to false) or non-blocking (set to true) status.
In addition, the WaitOne method can contain two parameters:
WaitOne (int millisecondsTimeout, bool exitContext)
MillisecondsTimeout: the number of milliseconds to wait, or the value is Timeout. Infinite (-1), which indicates waiting for an indefinite period of time.
If exitContext is true, exit the synchronization domain of the context (for example, in the synchronization context) and obtain it again later. Otherwise, the value is false.
That is to say, the waiting period can be added. If the waiting synchronization object has never been Set (), the program will be stuck, so a time period can be placed in the WaitOne method, the Unit is milliseconds.

 

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.