Primitive thread synchronization -- kernel mode construction (WaitHandle, EventWaitHandle, AutoResetEvent, ManualResetEvent, Semaphore, Mutex)

1, Kernel mode construction

The kernel mode construction adopts the windows operating system to synchronize threads, which is much slower than the construction of user modes such as volatileread, volatilewrite and interlocked. Compared with the construction of user mode, it also has its own advantages:

1. There is no need to occupy cpu "spin" like user mode and waste cpu resources.

2. Kernel mode can synchronize threads running in different processes on the same machine.

3. Synchronization between local and managed threads can be realized.

4. A thread can be blocked until all or part of the kernel objects in a collection are available. (WaitAll,WaitAny)

5. When blocking a thread, you can specify a timeout value. After this time, the blocking will be released.

2, FCL provides the kernel pattern construction hierarchy

WaitHandle (abstract class)

    |-EventWaitHandle

         |-AutoResetEvent

         |-ManualResetEvent

    |-Semaphore

    |-Mutex

They all inherit the WaitHandle abstract class. WaitHandle provides the following common static methods:

WaitOne: blocks the calling thread until a signal is received.

WaitAny: blocks the calling thread until any signal is received.

WaitAll: blocks the calling thread until all signals are received.

SingleAndWait: sends a signal to the specified kernel object and waits for another kernel object to receive the signal.

Close/Dispose: close the kernel object handle.

2.1 EventWaitHandle

It belongs to event, which is a Boolean variable maintained by the kernel. If the event is false, the thread waiting on the event is blocked; If the event is true, unblock. It has two main methods:

Set: set the event to true.

ReSet: set the event to false.

Note: during initialization, we can specify the initial value of the event. For example, the following example specifies that the initial event is false.

            EventWaitHandle ewh = new EventWaitHandle(false, EventResetMode.AutoReset);//Equivalent to AutoResetEvent
            EventWaitHandle ewh = new EventWaitHandle(false, EventResetMode.ManualReset);//Equivalent to ManualResetEvent

I only heard the voice of the architect from the architect's office: It's hard to buy and stay in spring because of the thousands of searches on the xiubi wall and the thousands of stacks of elm money. Who will match the first couplet or the second couplet?

2.2 AutoResetEvent

AutoResetEvent is a simple wrapper of EventWaitHandle without any additional logic inside. Its biggest feature is that after calling the Set method to Set the event to true, after one of the waiting threads is executed, it will automatically call the Reset method to Set the event signal to false to block other threads. It is equivalent to putting a thread in, and the door closes automatically (automatic door).

For example, use AutoResetEvent to implement a simple thread synchronization lock.

This code is by Java Architect must see network-Structure Sorting
        private class SimpleWaitLock : IDisposable
        {
            //Initialization must be true. Otherwise, the first thread calling the Enter method will be blocked
            private AutoResetEvent are = new AutoResetEvent(true);

            #region IDisposable 

            public void Enter()
            {
                are.WaitOne();//After the first thread calls this method, the event will be false and other threads will be blocked
                Console.WriteLine("thread={0}", Thread.CurrentThread.ManagedThreadId);
            }
            public void Exit()
            {
                are.Set();//When exiting, set the event signal to true, and set it to false immediately after putting a thread in (call reset)
            }
            public void Dispose()
            {
                are.Dispose();
            }

            #endregion
        }

2.3 ManualResetEvent

ManualResetEvent is a simple wrapper of EventWaitHandle, and there is no additional logic inside. The only difference between it and AutoResetEvent is that after calling the Set method and setting the event to true, the Reset method will not be called, which will cause the event to remain true and multiple other waiting threads will be executed until you manually call the Reset method. It is equivalent to that you need to close the door manually (non automatic door) after you open the door.

2.4 Semaphore

Semaphore is an Int32 variable maintained by the kernel. When the semaphore is 0, the thread waiting on the semaphore will block; When the semaphore is greater than 0, the blocking is released. Main methods:

Release (): it is an operation of adding 1

Release (int32 releasecount): it is an operation of adding releasecount.

When initializing semaphore, you can specify the maximum and minimum semaphore values.

Use semphore to realize the synchronization lock with the same function:

        private class SimpleWaitLock : IDisposable
        {
            //Initialization specifies that the count value is 1, allowing the first thread to be available
            private Semaphore sp = new Semaphore(1, 1);

            #region IDisposable

            public void Enter()
            {
                sp.WaitOne();//After the first thread calls this method, the count value decreases by 1 and becomes 0, and other threads will be blocked
                Console.WriteLine("thread={0}", Thread.CurrentThread.ManagedThreadId);
            }
            public void Exit()
            {
                sp.Release();//Count value plus 1, other threads are available
            }
            public void Dispose()
            {
                sp.Dispose();
            }

            #endregion
        }

2.5 Mutex

mutex works very similar to Semaphore or AutoResetEvent with a count of 1. These three methods release only one waiting thread at a time. Main methods:

ReleaseMutex(): count minus 1

The biggest difference is that it can call WaitOne() repeatedly on the same thread, and then call ReleaseMutex () an equal number of times. Other waiting threads cannot be called until the count of Mutex is 0. This method may not be used in ordinary times.

Mutex can be used to prevent the application from starting again, which is often encountered in normal work.

Simple example:

This code is by Java Architect must see network-Structure Sorting
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            bool createNew;
            Mutex mutex = new Mutex(false, "ApplicationGuidName", out createNew);
            //Without starting, create a new one
            if (createNew)
            {
                Application.Run(new Form1());
            }
            else
            {
                // It's already started
                MessageBox.Show("The program has been started and cannot be started again!");
            }
        }

Note: you can also use Semaphore and EventWaithandle to realize the above functions. The principle is the same. But AutoResetEvent and ManualResetEvnet can't. They don't provide similar construction methods.

2.6 calling a method when a kernel mode becomes available

You can use ThreadPool The registerwaitforsingleobject method registers a method. This method is called automatically when an event receives a signal or the specified time expires.

This method is particularly useful for AutoResetEvent. But it is not suitable for ManualResetEvent, because you need to call the Reset method manually, otherwise you will call this method indefinitely.

        private void TestAutoCallBack()
        {
            AutoResetEvent mre = new AutoResetEvent(false);
            //Set the timeout to 2000ms
            ThreadPool.RegisterWaitForSingleObject(mre, new WaitOrTimerCallback(WaitCallBack),
                "123", 2000, false);

            //Send a signal
            mre.Set();

            //Deliberately wait for 3000ms
            Thread.Sleep(3000);
        }

        //This method is called when there is a signal or timeout
        private void WaitCallBack(object state, bool timeOut)
        {
            Console.WriteLine("is time out = {0}", timeOut);
        }

Operation results:

is time out = False //Call when getting signal
is time out = True  //Timed out call
is time out = True  //Timed out call

Added by rdimaggio on Sun, 27 Feb 2022 07:46:27 +0200