The article takes you to know. Net implements mutex based on Threading. Mutex

  • 2021-11-29 23:32:39
  • OfStack

This article mainly explains. Net implements mutex based on Threading. Mutex

Implementation of basic mutex

Basic concepts: Like spin lock 1, The mutex provided by the operating system has a numerical value indicating whether the lock has been acquired. The difference is that when the lock acquisition fails, It does not retry repeatedly, But also puts the thread into a waiting state, And adds the thread object to the queue associated with the lock, When another thread releases the lock, it checks whether there are threaded objects in the queue. If yes, the operating system is notified to wake up the thread, because the thread object acquiring the lock is not running, even if the lock is not released for a long time, it will not consume CPU resources, but the time for letting the thread enter the waiting state and wake up from the waiting state is longer than the nanosecond time for retrying the spin lock

Differences between windows and linux

In windows system, the mutex is created by CreateMuteEx function. When the lock is acquired, the WaitForMultipleObjectsEx function will be called, and when the lock is released, the ReleaseMutex function will be called. The thread enters the waiting state and wakes up by the system
The Mutex object on Linux is simulated by the internal interface of NetCore, The result contains the state value of the lock and the queue of waiting threads. Each managed thread will be associated with an pthread_mutex_t object and an pthread_cond_t object, which are provided by pthread class library. The thread that fails to acquire the lock will adjust the price to the queue pthread_cond_wait function to wait, and the other thread will call pthread_cond_signal function to wake up when it sees a thread in the queue when releasing the lock.

Basic Mutex Code Implementation


 public static class MutexDemo
    {
        private static readonly Mutex _lock = new Mutex(false, null);
        private static int _counterA = 0;
        private static int _counterB = 0;

        public static void IncrementCounters()
        {
            // Acquisition lock 
            _lock.WaitOne();
            try
            {
                ++_counterA;
                ++_counterB;
            }
            finally
            {
                // Release lock 
                _lock.ReleaseMutex();
            }
        }

        public static void GetCounters(out int counterA, out int counterB)
        {
            _lock.WaitOne();
            try
            {
                counterA = _counterA;
                counterB = _counterB;
            }
            finally
            {
                // Release lock 
                _lock.ReleaseMutex();
            }
        }


    }

Mutual exclusion lock (recursive lock)

Basic concept: The lock provided by Mutex can be reentered. The thread that has acquired the lock can perform the operation of acquiring the lock again, but the operation of releasing the lock should also be performed the same number of times. The reentrant lock is also called recursive lock.

Implementation principle: Recursive lock internal use of a counter to record the number of entry, the same as a thread every time to obtain 1 plus 1, release 1 minus 1, minus 1 if the calculator is 0 on the implementation of the real release operation. It is meaningless to use recursive locks in a single function, and 1 is nested in multiple functions

Code implementation


public static class MutexRecursionDemo
    {
        private static Mutex _lock = new Mutex(false, null);
        private static int _counterA = 0;
        private static int _counterB = 0;

        public static void IncrementCountersA()
        {
            // Acquisition lock 
            _lock.WaitOne();
            try
            {
                ++_counterA;
            }
            finally
            {
                // Release lock 
                _lock.ReleaseMutex();
            }
        }

        public static void IncrementCountersB()
        {
            // Acquisition lock 
            _lock.WaitOne();
            try
            {
                ++_counterB;
            }
            finally
            {
                // Release lock 
                _lock.ReleaseMutex();
            }
        }

        public static void IncrementCounters()
        {
            // Acquisition lock 
            _lock.WaitOne();
            try
            {
                IncrementCountersA();
                IncrementCountersB();
            }
            finally
            {
                // Release lock 
                _lock.ReleaseMutex();
            }
        }


        public static void GetCounters(out int counterA, out int counterB)
        {
            _lock.WaitOne();
            try
            {
                counterA = _counterA;
                counterB = _counterB;
            }
            finally
            {
                // Release lock 
                _lock.ReleaseMutex();
            }
        }
    }

Mutex (used across processes)

Basic concepts: Mutex supports the use of boast processes, Created by passing in the name through the second parameter name of the constructor, When the name starts with Walterlv. Mutex, a lock with this name is shared with a process of 1 user. If one process acquires a lock, another process needs to wait to acquire a lock with the same name before releasing the lock. If the process acquires the lock but does not call the method to release the lock before exiting, the lock will be automatically released, and other cities currently waiting for the lock will be subject to AbandonedMuteException exception.

linux is implemented by means of temporary files

Implementation code


public static class MutexDemo
    {
        private static Mutex _lock = new Mutex(false, @"Walterlv.Mutex");
        private static int _counterA = 0;
        private static int _counterB = 0;

        public static void IncrementCounters()
        {
            // Acquisition lock 
            _lock.WaitOne();
            try
            {
                ++_counterA;
                ++_counterB;
            }
            finally
            {
                // Release lock 
                _lock.ReleaseMutex();
            }
        }

        public static void GetCounters(out int counterA, out int counterB)
        {
            _lock.WaitOne();
            try
            {
                counterA = _counterA;
                counterB = _counterB;
            }
            finally
            {
                // Release lock 
                _lock.ReleaseMutex();
            }
        }
    }

The above code only needs to be copied 1, started in multiple programs, call MutexDemo. IncrementCounters () can see the effect


Related articles: