Thread Synchronization is inevitable when writing multi-threaded programs. 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 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, you do not need to use the thread synchronization technology to ensure data integrity and correctness.
Remember this:
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. This method can solve the problems raised at the beginning of the article. For example, before supervisor A wants to handle T Jun's salary, he locks T Jun first and then retrieves the current
Count value. After processing, T Jun's lock will be lifted. 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 was originally an operation of multiple threads. Once a lock statement is encountered, these threads only need to queue for processing and form the same
Single-threaded operations.
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
{
// Sample by Kwanhong Young, see http://bbs.helloit.info more/
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
The value of count 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 the exclusive code segment, which may prevent the "token" object from being released, so that the program will always die.
Continue.
Therefore, you must handle exceptions in the exclusive code segment. For example, the following code is incorrect:
Public void Add (int n)
{
// See more: http://bbs.helloit.info/
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)
{
// See more: http://bbs.helloit.info/
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 ();
}