Lock System in multiple threads (III)-WaitHandle, AutoResetEvent, ManualResetEvent, manualresetevent
Introduction
This chapter describes the Thread Synchronization Methods, events, and semaphores constructed in kernel mode.
Directory
I. Theory
Ii. WaitHandle
Iii. AutoResetEvent
4. ManualResetEvent
V. Summary
I. Theory
We know that thread synchronization can be divided into user mode construction and kernel mode construction.
Kernel Mode Structure: it is used by the windows system and scheduled by kernel objects. The kernel object is a memory block in the system address space, which is created and maintained by the system.
Kernel objects are owned by the kernel rather than processes. Therefore, different processes can access the same kernel object, such as processes, threads, jobs, events, files, semaphores, the mutex is a kernel object.
Semaphores, mutex, and events are kernel objects that windows specifically uses to help us synchronize threads.
For thread synchronization, the kernel object has only two States: trigger (terminate, true) and not trigger (non-terminate, false ). Scheduling is not triggered. Scheduling is triggered.
User Mode Construction: The thread is coordinated by special CPU commands. The volatile Implementation described above is one type, and Interlocked is the same. It can also be called non-blocking thread synchronization.
Ii. WaitHandle
In windows programming, after a kernel object is created through API, a handle is returned, which is the index of each process handle table, then we can get the pointer, mask, and identifier of the kernel object.
The WaitHandle abstract base class encapsulates the handle of a windows Kernel Object. Let's take a look at the source code of one of the WaitOne functions (slightly simplified ).
Public virtual bool WaitOne (TimeSpan timeout) {return WaitOne (timeout, false);} [System. security. securitySafeCritical] // auto-generated [SuppressMessage ("Microsoft. concurrency "," CA8001 ", Justification =" Reviewed for thread-safety. ")] private bool WaitOne (long timeout, bool exitContext) {return InternalWaitOne (safeWaitHandle, timeout, hasThreadAffinity, exitContext);} [System. security. securit YCritical] internal static bool InternalWaitOne (SafeHandle waitableSafeHandle, long millisecondsTimeout, bool hasThreadAffinity, bool exitContext) {Contract. endContractBlock (); int ret = WaitOneNative (waitableSafeHandle, (uint) millisecondsTimeout, hasThreadAffinity, exitContext); if (ret = WAIT_ABANDONED) {forward ();} return! = WaitTimeout);} // call win32 waitforsingleobjectEx [System. security. securityCritical] [ResourceExposure (resourcworkflow. none)] [methodimplattritions (MethodImplOptions. internalCall)] private static extern int WaitOneNative (SafeHandle waitableSafeHandle, uint millisecondsTimeout, bool hasThreadAffinity, bool exitContext );
WaitAll and WaitAny call the waitformultipleobjectsEx function in win32.
SignalAndWaitOne calls the signalandwait function in win32.
The timeout value is set for Calling api ex. If we do not upload data in c #, the default value is-1, indicating that the request is waiting for an indefinite period of time.
The SafeWaitHandle field contains a win32 kernel object handle.
I understand that WaitHandle is easy to handle. Let's take a look at its derived type.
WaitHandle
| -- EventWaitHandle event construction.
| -- AutoResetEvent
| -- ManualResetEvent
| -- Semaphore construction.
| -- Mutex
The first chapter of Semaphore and mutex has already been mentioned. Let's take a look at other.
Iii. AutoResetEvent
The example is as follows, with simple annotations. The description should be as close as possible to the system terminology.
Static void Main (string [] args) {// AutoResetEvent example // AutoResetEvent notifies the waiting thread of an event that has occurred. AutoResetEvent waitHandler = new AutoResetEvent (false); // false indicates that it is not terminated and is not triggered. New Thread () => {waitHandler. WaitOne (); // blocks the current Thread and waits for the underlying kernel object to receive a signal. Console. WriteLine ("receives the signal and starts processing. ");}). Start (); new Thread () => {Thread. sleep (1, 2000); Console. writeLine ("Sending signal"); waitHandler. set (); // sends a signal to the kernel object. Set the event object to non-terminating or false to cancel blocking. }). Start (); // waitHandler. Close (); // release the handle resource. // WaitHandler. Reset (); // manually set the event to a non-terminating State, false, and thread blocking. Console. ReadLine ();}
WaitOne blocks the thread and does not spin.
After Set () sends a signal, it sets the event status to false. This should be a two-step operation. The AutoResetEvent. set () function automatically performs the two steps together, which is very convenient.
4. ManualResetEvent
This is basically the same as above. manually reset the status literally. Let's look at the example.
ManualResetEvent manualWaitHandler = new ManualResetEvent (false); // false indicates non-termination, not triggered. New Thread () => {manualWaitHandler. WaitOne (); // block the current Thread object and wait for the signal. Console. WriteLine ("receives the signal and starts processing. "); ManualWaitHandler. Reset (); // manually set the event object status to non-terminated, false. ManualWaitHandler. WaitOne (); // The blocking wait here is invalid. Because the event object is still true, You must manually call reset. Console. WriteLine ("the second time the signal is received, start processing. ");}). Start (); new Thread () => {Thread. sleep (1, 2000); Console. writeLine ("Sending signal"); manualWaitHandler. set (); // send an OK signal to the event object .. Thread. Sleep (2000); Console. WriteLine ("second signal"); manualWaitHandler. Set () ;}). Start (); Console. ReadLine ();
The difference between the two is very small. In fact, it is the distinction between system APIs, not implemented by the net class library.
In the Win32Native class, we can see that the KERNEL32 api has such a parameter isManualReset.
[DllImport(KERNEL32, SetLastError=true, CharSet=CharSet.Auto, BestFitMapping=false)] [ResourceExposure(ResourceScope.Machine)] // Machine or none based on the value of "name" internal static extern SafeWaitHandle CreateEvent(SECURITY_ATTRIBUTES lpSecurityAttributes, bool isManualReset, bool initialState, String name);
V. Summary
The synchronization steps constructed based on the kernel mode are: hosting code-> User mode code-> kernel mode code, and vice versa. In this way, the performance will certainly not be better. Note the difference.
The user mode is constructed by using special CPU commands for atomic operations.
User mode code ,. It refers to the management code that calls the win32 code layer and then calls the kernel mode code.
Reference resources
1: CLR via c #
2: Fifth edition of windows core programming
If you have any errors, please point them out. For help, we recommend n (* too many rows *) n.
Author: Mr. mushroom
Source: http://www.cnblogs.com/mushroom/p/4198429.html