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 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 ". 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 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 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 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;