Methods for synchronizing objects to several threads in C #

Source: Internet
Author: User

Write MultithreadingProgramThread Synchronization is inevitable. What is thread synchronization?

For example, if there is a variable in a company that records the salary count of someone t = 100, there are two supervisors a and B (that is, the working thread) in the early hours, I took the value of this variable back.
After a while, supervisor a added 5 T's salary and returned the count variable. Then, supervisor B subtracted 3 T's salary and returned 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 ". HoweverCodeThe 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 the 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 functions of the same class are similar:
The role of the first type is to protect the execution of a code segment in an exclusive manner. If a second thread wants to access this object, it will be suspended. Wait until the exclusive
Code execution ends. Just like a bunch of people putting on a public toilet at the same time, this method can be used to solve the problem.ArticleQuestion raised at the beginning: Supervisor A should first lock t Jun before handling t Jun's salary, then take out the current Count value, and then unlock t Jun after processing. If supervisor B also wants to retrieve the Count value when supervisor a processes the salary, it can only continue after supervisor a completes the processing. 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 tool class with an int variable and the add and delete methods. The add method increases the value of the int variable and the delete method reduces the value of the int variable:

Public class tools
{
Private int COUNT = 100;
Public void add (int n)
{
Count + = N;
}

Public void Delete (int n)
{
Count-= N;
}
}

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;
}
}
}

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 first
After the curly brackets of a lock statement are completed, the token is released and quickly falls into the hands of the second thread, and other people 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 );
}
}

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 ();
}
}

Waitone is the waiting method and waits until mutex is released. Initially, the mutex object is in the release state, and once the waitone method is executed, it
It is captured until the releasemutex method is called.
Note that an exception occurs in an exclusive code segment, which may prevent the "token" object from being 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
//... Code that may cause exceptions
//... N lines of code are omitted here
Mut. releasemutex ();
}
Catch
{
Console. writeline ("error .");
}
}

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
//... Code that may cause exceptions
//... N lines of code are omitted here
}
Catch
{
Console. writeline ("error .");
}
Mut. releasemutex ();
}

Now let's talk about the second type:
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 work
Console. writeline ("have you received it, I sent the response :)");
Console. Readline ();
}

}

Public class boy
{
Manualresetevent ent;

Public boy (manualresetevent E)
{
Ent = E;
}

Public void sendflower ()
{
Console. writeline ("sending flowers ");
For (INT I = 0; I <10; I ++)
{
Thread. Sleep (200 );
Console. Write ("..");
}
Console. writeline ("\ r \ n flowers have been delivered to mm, Boss ");

Ent. Set (); // notification blocking program
}
}

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 work
Console. writeline ("I have 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 ("sending flowers ");
For (INT I = 0; I <10; I ++)
{
Thread. Sleep (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.
}
}

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 (if it is 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 is not 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.