. NET multithreaded Programming (3)--Thread synchronization

Source: Internet
Author: User
Tags exit in mutex

as you go deeper into multithreaded learning, you may find it necessary to understand some of the issues related to thread-sharing resources. The. NET Framework provides a number of classes and data types to control access to shared resources.

consider a situation that we often encounter: there are global variables and shared class variables, and we need to update them from different threads. You can accomplish such tasks by using the System.Threading.Interlocked class, which provides atomic, non-modular integer update operations.

There is a piece of code that you can use to lock an object by using the System.Threading.Monitor class so that it cannot be accessed by other threads temporarily.

an instance of the System.Threading.WaitHandle class can be used to encapsulate an operating system-specific object that waits for exclusive access to a shared resource. This is especially true for interoperability issues with non-managed code.

System.Threading.Mutex is used to synchronize multiple complex threads, and it also allows single-threaded access.

synchronization event classes such as ManualResetEvent and AutoResetEvent support a class to notify threads of other events.

The thread synchronization problem is not discussed, which is equal to the lack of knowledge of multithreaded programming, but we have to be very cautious about using multi-threaded synchronization. When using thread synchronization, we have to be able to correctly determine that the object and method are likely to cause a deadlock (the deadlock is that all the threads are stopped, and all the others are releasing resources). There is also the problem of the stolen data (refers to the same time multiple threads to manipulate the data caused by the inconsistency), this is not easy to understand, so to speak, there are X and y two threads, thread x from the file to read data and write data to the structure, thread y from this data structure to read and send the data to other computers. Assuming that Y reads data while X writes the data, it is clear that Y reads data that is inconsistent with the data that is actually stored. This situation is obviously something we should avoid. A small number of threads will cause the problem to occur much less, and access to shared resources is also better synchronized.

the. NET Framework's CLR provides three ways to complete the methods and domains for shared resources, such as global variable fields, specific code snippets, static and instantiated.

(1) Code domain synchronization: Use the Monitor class to synchronize the entire code of a static/instantiated method or part of a code snippet. Synchronization of static domains is not supported. In the instantiated method, the this pointer is used for synchronization, and in the static method, the class is used for synchronization, which is discussed later.

(2) Manual synchronization: Use different synchronization classes (such as WaitHandle, mutexes, ReaderWriterLock, ManualResetEvent, AutoResetEvent and interlocked, etc.) to create their own synchronization mechanism. This synchronization requires you to manually synchronize the different domains and methods, which can also be used for inter-process synchronization and deadlock cancellation caused by waiting on shared resources.

(3) Context synchronization: Use SynchronizationAttribute to create simple, automatic synchronization for ContextBoundObject objects. This synchronization method is only used for the synchronization of the instantiated methods and domains. All objects in the same context domain share the same lock. Monitor Class

at a given time and the specified code snippet can only be accessed by one thread, the Monitor class is well suited for this case of thread synchronization. The methods in this class are static, so there is no need to instantiate this class. Some of the following static methods provide a mechanism to synchronize access to objects to avoid deadlocks and maintain data consistency.

Monitor.Enter Method: Gets an exclusive lock on the specified object.

Monitor.TryEnter Method: Attempts to obtain an exclusive lock on the specified object.

Monitor.Exit Method: Frees an exclusive lock on the specified object.

Monitor.Wait Method: Releases the lock on the object and blocks the current thread until it acquires the lock again.

Monitor.pulse method: Notifies a thread in the waiting queue of a change in the lock object state.

Monitor.pulseall method: Notifies all waiting thread object state changes. Access to the code snippet can be synchronized by locking and unlocking the specified object.Monitor.Enter, Monitor.TryEnter andThe monitor.exit is used to lock and unlock the specified object. Once a lock is obtained (called Monitor.Enter) for the specified object (code snippet), no other thread can acquire the lock. For example, thread x obtains an object lock that can be freed (called monitor.exit (object) or monitor.wait). When this object lock is released, theMonitor.pulse method and the Monitor.pulseall method notifies the ready queue that the next thread is making and all other ready queue threads will have the opportunity to acquire an exclusive lock. Thread x frees the lock and thread y obtains the lock while calling Monitor.Wait's thread x into the wait queue. When the thread (thread Y) from the currently locked object is under pulse or PulseAll, the thread waiting for the queue enters the ready queue. monitor.wait only returns when Thread X gets the object lock back. If the thread that owns the lock (thread Y) does not call pulse or PulseAll, the method may be locked by an indeterminate lock. Pulse, PulseAll and wait must be the code snippet that is being synchronized is called. For each synchronized object, you need a pointer to the thread that currently owns the lock, a ready queue, and a wait queue (containing a thread that needs to be notified of the state change of the locked object).

you might ask, what happens when two threads call Monitor.Enter at the same time ? No matter how close the two threads call Monitor.Enter, there must actually be one in front, one in the back, so there will always be only one get object lock. Since Monitor.Enter is an atomic operation, it is not possible for a CPU to prefer one thread to another. In order to get better performance, you should delay the acquisition of a lock on a thread after the call and immediately release the object lock of the previous thread. For private and internal objects, locking is possible, but for external objects It is possible to cause deadlocks because unrelated code may lock the same object for different purposes.

If you want to lock a piece of code, the best thing is to add a set of lock statements inside a try statement, and put Monitor.Exit in the finally statement. For the entire code snippet lock, you can use MethodImplAttribute (in the System.Runtime.CompilerServices namespace) class to set the synchronization value in its constructor. This is an alternative approach, and when the locking method returns, the lock is freed. If you need to release the lock quickly, you can use the declaration of the Monitor class and C # lock instead of the method described above.

Let's look at a section of code that uses the Monitor class:
public void Some_method () {int a=100; int b=0; Monitor.Enter (this); Say we do something here. int c=a/b; Monitor.Exit (this); }

The code above will cause problems. When the code runs to int c=a/b, an exception is thrown andMonitor.Exit will not be returned. So this program will hang, and the other threads will not get locks. There are two ways to solve the problem above. The first method is to put the code inside the try...finally and call Monitor.Exit at finally , so that the lock will eventually be released. The second approach is to use the C # Lock () method. Calling this method has the same effect as calling Monitoy.enter. However, once the code execution goes out of scope, releasing the lock will not happen automatically. See the following code :

public void Some_method () {int a=100; int b=0, lock (this),//say we do something here. int c=a/b;}

  

The C # Lock declaration provides the same functionality as Monitoy.enter and Monitoy.exit, which is used in situations where your code snippet cannot be interrupted by another independent thread. WaitHandle Class

the WaitHandle class is used as a base class, which allows multiple wait operations. This class encapsulates the synchronous processing of Win32. The WaitHandle object notifies other threads that it requires exclusive access to the resource, and other threads must wait until WaitHandle no longer uses the resource and the wait handle is not used. Here are some of the classes inherited from it:

Mutex class: Synchronization primitives can also be used for inter-process synchronization.

AutoResetEvent: Notifies one or more waiting threads that an event has occurred. This class cannot be inherited.

ManualResetEvent: Occurs when one or more thread events that are waiting are notified that the event has occurred. This class cannot be inherited.

These classes define a number of signaling mechanisms that allow exclusive access to resources for appropriation and release. They have two states: signaled and nonsignaled. The wait handle for the signaled state does not belong to any thread unless it is in the nonsignaled state. The thread that owns the wait handle is no longer using the Set method when the wait handle is used, and other threads can call the Reset method to change the state or any of the WaitHandle methods require a wait handle, as shown below:

WaitAll: Waits for all elements in the specified array to receive a signal.

WaitAny: Waits for any element in the specified array to receive a signal.

WaitOne: When overridden in a derived class, blocks the current thread until the current WaitHandle receives a signal.
These wait methods block threads until one or more of the synchronization objects receive a signal.

The WaitHandle object encapsulates an operating system-specific object that waits for exclusive access to a shared resource, whether it is Milo code or unmanaged code. But it's not as lightweight as monitor, and monitor is a fully managed code and is very efficient in using operating system resources.
Mutex Class
A mutex is another way of accomplishing synchronization between threads and across processes, and it also provides synchronization between processes. It allows one thread to monopolize the sharing of resources while blocking access to other threads and processes. The name of the mutex is a good illustration of its owner's exclusive possession of the resource. Once a thread has a mutex, the other threads that want the mutex will hang until the owning thread releases it. The Mutex.releasemutex method is used to release the mutex, and a thread can call the wait method multiple times to request the same mutex, but must invoke the same number of Mutex.releasemutex when releasing the mutex. If no thread occupies the mutex, then the state of the mutex becomes signaled, otherwise it is nosignaled. Once the state of the mutex becomes signaled, the next thread waiting for the queue will get the mutex. The mutex class corresponds to the CreateMutex of Win32, and the method of creating the mutex object is very simple, which is commonly used in the following ways:

a thread can get ownership of a mutex by calling WaitHandle.WaitOne or WaitHandle.WaitAny or WaitHandle.WaitAll. If the mutex does not belong to any thread, the above call will cause the thread to own the mutex, and WaitOne will return immediately. But if there are other threads that own mutex,waitone will be stuck in indefinitely waiting until the mutex is acquired. You can specify in the WaitOne method that the parameter is the time to wait and avoid waiting for the mutex indefinitely. Calling close acts on the mutex to release the owning. Once the mutex is created, you can use the GetHandle method to obtain the handle of the mutex for the WaitHandle.WaitAny or WaitHandle.WaitAll method.

Here is an example:
public void Some_method () {int a=100; int b=20; Mutex Firstmutex = new Mutex (false); Firstmutex.waitone (); Some kind of processing can be do here. Int x=a/b; Firstmutex.close (); }

  

in the example above, the thread creates the mutex, but the start does not declare that it owns it, and the mutex is owned by calling the WaitOne method. Synchronization Events
The synchronization time is something that waits for a handle to notify other threads of what is going on and that the resource is available. They have two states:signaled and nonsignaled. AutoResetEvent and ManualResetEvent are such synchronization events. AutoResetEvent Class
This class can notify one or more threads of the occurrence of an event. When a waiting thread is released, it transitions the state to signaled. Use the Set method to change its instance state to signaled. But once the waiting thread becomes signaled by the notification time, its turntable will automatically become nonsignaled. If no thread listens for events, the turntable remains signaled. This class cannot be inherited. ManualResetEvent Class
This class is also used to notify that one or more thread events have occurred. Its status can be set and reset manually. The manual reset time will remain in the signaled state until Manualresetevent.reset is set to nonsignaled, or the status is nonsignaled until Manualresetevent.set is set to signaled. This class cannot be inherited. Interlocked Class
It provides synchronization of variable access shared between threads, it operates atomically, and is shared by the thread. You can pass interlocked.increment or Interlocked.decrement to increase or decrease shared variables. It's a bit of atomic manipulation, which means that these methods can increment the parameters of an integer and return a new value, all in one step. You can also use it to specify the value of a variable or to check whether two variables are equal. If equal, the value of one of the variables is substituted with the specified value.

. NET multithreaded Programming (3)--Thread 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.