C#Thread Learning Note 5: Thread Synchronization--Event Construction

Keywords: C# Windows

Extract this note from: https://www.cnblogs.com/zhili/archive/2012/07/23/Event_Constructor.html And record the learning process for future reference.

(Thread synchronization mentioned earlier is mainly user mode (as defined in CLR Via C#, which refers to threading synchronization in two ways: first, user mode construction, and kernel mode construction). For kernel mode construction (which refers to the construction of operating system kernel objects), we use classes in the.NET Framework

For example, methods in AutoResetEvent and Semaphore that synchronize threads call kernel objects in the operating system to synchronize threads, and then the threads are converted from managed to kernel code.User mode constructs, because the operating system kernel object is not invoked, the thread will only use

Executed on the managed code of the user.

1. Introduction to WaitHandle base classes

The System.Threading namespace provides an abstract base class for WaitHandle, which is a handle that wraps a Windows kernel object (a handle can be understood as a number that indicates an object instance,

Specifically, you can consult the data for a deeper understanding, and it is also important to just put forward an understanding handle here.

Classes derived from the WaitHandle class are provided in the.NET Framework and their inheritance relationship is:

    WaitHandle

     EventWaitHandle

            AutoResetEvent

            ManualResetEvent

        Semaphore

        Mutex

When we use constructors to instantiate objects of AutoResetEvent, ManualResetEvent, Semaphore, Mutex classes, the Win32 CreateEvent or CreateEvent functions are called internally

Or the CreateSemaphore or CreateMutex functions, which call returns handle values that are stored in the SafeWaitHandle field defined by the WaitHandle base class.

2. Event class implements thread synchronization

2.1 AutoResetEvent

2.1.1 Starts with the constructor for the AutoResetEvent class, which is defined as:

    public AutoResetEvent(bool initialState);

The initial state of a bool type is used in the constructor to set the state of the AutoResetEvent object.If you want to set the initial state of the AutoResetEvent object to terminate, the incoming bool value is true;

To set to non-terminating, the incoming bool value is false.(

2.2.2 WaitOne method definition:

    public virtual bool WaitOne(int millisecondsTimeout);

This method is used to block threads and returns false if no signal has been received at the specified time interval.

The Set method is called to signal the release of the waiting thread.

The WaitOne and Set methods appear in pairs during use:

One is used to block threads and wait for signals;

) A wait thread is released (that is, a set method is called to send a signal, when WaitOne receives the signal, the blocked thread is released and the thread can continue to run.)

A thread waits for a signal by calling the WaitOne method of AutoResetEvent, and if the AutoResetEvent object is in a non-terminating state, the thread is blocked until the thread invokes the Set method to resume thread execution.

If AutoResetEvent is in a terminated state, the thread is not blocked, and AutoResetEvent immediately releases the thread and returns to a non-terminated state (indicating a state in which threads are using resources).

The following code demonstrates the use of AutoResetEvent:

    class Program
    {
        //create object
        public static AutoResetEvent autoResetEvent = new AutoResetEvent(false);

        static void Main(string[] args)
        {
            #region Thread synchronization: AutoResetEvent Use
            Console.WriteLine("Main thread start run at: " + DateTime.Now.ToLongTimeString());
            Thread thread = new Thread(WaitOneMethod);
            thread.Start();

            //Blocking main thread for 3 seconds
            Thread.Sleep(3000);

            //Release Threads
            autoResetEvent.Set();
            Console.Read();
            #endregion
        }

        /// <summary>
        /// WaitOne Method
        /// </summary>
        public static void WaitOneMethod()
        {
            autoResetEvent.WaitOne();
            Console.WriteLine("Method restart run at: " + DateTime.Now.ToLongTimeString());
        }
    }

The results are as follows:

When you create an object, change it to public static AutoResetEvent autoResetEvent = new AutoResetEvent(true); the same time you see the output.Because when set to True, means this time

Already terminated.Therefore, autoResetEvent.Set() can be interpreted as setting the state of autoResetEvent to the termination state, thereby releasing the thread.(

The WaitOne method without parameters is used above, which means that the thread is blocked indefinitely until an event is received (a signal is sent via the Set method).

With bool WaitOne (int milliseconds Timeout), when the time-out occurs, the thread will no longer block the thread and let it continue running even if it does not receive a signal from Set, except that the WaitOne method returns a different value:

The return value is True when the Set signal is received, otherwise the return value is false.

The following code demonstrates the use of WaitOne (milliseconds Timeout):

    class Program
    {
        //create object
        public static AutoResetEvent autoResetEvent = new AutoResetEvent(false);

        static void Main(string[] args)
        {
            #region Thread synchronization: WaitOne(millisecondsTimeout)Use
            Console.WriteLine("Main thread start run at: " + DateTime.Now.ToLongTimeString());
            Thread thread = new Thread(WaitOneTimeoutMethod);
            thread.Start();

            //Blocking main thread for 3 seconds
            Thread.Sleep(3000);

            //Release Threads
            autoResetEvent.Set();
            Console.Read();
            #endregion
        }

        /// <summary>
        /// WaitOneTimeout Method
        /// </summary>
        public static void WaitOneTimeoutMethod()
        {
            if (autoResetEvent.WaitOne(2000))
            {
                Console.WriteLine("Get signal to work.");
                Console.WriteLine("Method restart run at: " + DateTime.Now.ToLongTimeString());
            }
            else
            {
                Console.WriteLine("Time out to work.");
                Console.WriteLine("Method restart run at: " + DateTime.Now.ToLongTimeString());
            }
        }
    }

The results are as follows:

If Thread.Sleep(3000); is set to Thread.Sleep(1000); then the thread will receive a signal from Set, and the result will be Get signal to work, with a time difference of only one second.

2.2 ManualResetEvent (Manual Reset Event)

ManualResetEvent and AutoResetEvent are used similarly because they are derived from the EventWaitHandle class, but they are different:

When 2.2.1AutoResetEvent is terminated (true), the thread will not be blocked if it calls the WaitOne method.AutoResetEvent immediately releases the thread and returns to a non-terminating state (false),

After that, if the thread calls the WaitOne method again, the thread will be blocked.(Note: Calling the WaitOne method automatically changes the state, only if the initial state is terminated.)

When 2.2.2 ManualResetEvent is terminated (true), the thread will not be blocked if it calls the WaitOne method.This ManualResetEvent immediately releases the thread but does not return to a non-terminating state (false),

Unless we manually change the state to a terminated state (false), the thread will not be blocked after that if it calls the WaitOne method again.

The following code demonstrates the difference between the two:

    class Program
    {
        //create object
        public static AutoResetEvent autoResetEvent = new AutoResetEvent(false);
        public static ManualResetEvent manualResetEvent = new ManualResetEvent(false);

        static void Main(string[] args)
        {
            #region Thread synchronization: ManualResetEvent Use
            Console.WriteLine("Main thread start run at: " + DateTime.Now.ToLongTimeString());

            Thread threadAuto = new Thread(AutoResetEventMethod);
            threadAuto.Start();
            autoResetEvent.Set();
            threadAuto = new Thread(AutoResetEventMethod);
            threadAuto.Start();

            Thread threadManual = new Thread(ManualResetEventMethod);
            threadManual.Start();
            manualResetEvent.Set();
            threadManual = new Thread(ManualResetEventMethod);
            threadManual.Start();

            Console.Read();
            #endregion
        }

        /// <summary>
        /// AutoResetEvent Method
        /// </summary>
        public static void AutoResetEventMethod()
        {
            autoResetEvent.WaitOne();
            Console.WriteLine("Autoresetevent method restart run at: " + DateTime.Now.ToLongTimeString());
        }

        /// <summary>
        /// ManualResetEvent Method
        /// </summary>
        public static void ManualResetEventMethod()
        {
            manualResetEvent.WaitOne();
            Console.WriteLine("Manualresetevent method restart run at: " + DateTime.Now.ToLongTimeString());
        }
    }

The results are as follows:

2.3 Synchronization across processes

Kernel mode constructs synchronize threads in different processes on the same machine, so AutoResetEvent can be used to do this.You need to name AutoResetEvent at this point, but AutoResetEvent only provides a constructor with one parameter. How do you do that?

The solution still exists because AutoResetEvent inherits from the EventWaitHandle class, which has multiple constructors.

In addition to the previous method of creating AutoResetEvent objects, you can also construct AutoResetEvent objects by EventWaitHandle autoEvent = new EventWaitHandle (false, EventResetMode.Auto,'My'); this method specifies the name.

The following code demonstrates thread synchronization across processes:

First process code:

    class Program
    {
        //create object
        public static EventWaitHandle autoEventFirst = new EventWaitHandle(false, EventResetMode.AutoReset, "First");
        public static EventWaitHandle autoEventSecond = new EventWaitHandle(false, EventResetMode.AutoReset, "Second");

        static void Main(string[] args)
        {
            #region Thread synchronization: Thread synchronization across processes
            Console.WriteLine("First main thread start run at: " + DateTime.Now.ToLongTimeString());
            Thread thread = new Thread(EventWaitHandleMethod);
            thread.Start();

            //To have time to start another process
            Thread.Sleep(15000);
            autoEventFirst.Set();
            autoEventSecond.Set();
            Console.Read();
            #endregion
        }

        /// <summary>
        /// EventWaitHandle Method
        /// </summary>
        public static void EventWaitHandleMethod()
        {
            autoEventFirst.WaitOne();
            Console.WriteLine("First method start at:" + DateTime.Now.ToLongTimeString());
        }
    }

Second process code:

    class Program
    {
        //create object
        public static EventWaitHandle autoEventSecond = new EventWaitHandle(false, EventResetMode.AutoReset, "Second");
        static void Main(string[] args)
        {
            Console.WriteLine("Second main thread start run at: " + DateTime.Now.ToLongTimeString());
            Thread thread = new Thread(EventWaitHandleMethod);
            thread.Start();
            Console.Read();
        }

        /// <summary>
        /// EventWaitHandle Method
        /// </summary>
        public static void EventWaitHandleMethod()
        {
            autoEventSecond.WaitOne();
            Console.WriteLine("Second method start at:" + DateTime.Now.ToLongTimeString());
        }
    }

The results are as follows:

You can see from the results that the autoEventSecond.Set() of the first process; after the signal is sent, the second process can receive and release the thread.(

Posted by caster001 on Sat, 07 Dec 2019 21:41:07 -0800