Talk about multi-threaded way of thinking

Some time ago read carefully the information on multithreading, local threads used in the project a lot, but, when after reading an article about Jeffrey locks, found themselves though have been using multiple threads, but the lack of multi-threaded programming needs to do thinking! I would like to start from Jeffrey's Optex (lock), from which to talk about my experience things.

   In NET, we use the most is the locking mechanism lock, is simple to use, just a few lines can be achieved, for example:

public class TestThreading
{
    private System.Object lockThis = new System.Object();
    public void Function()
    {
        lock (lockThis)
        {
            // Access thread-sensitive resources.
        }
    }
}
In fact, we also understand that, lock is not locked, but a simple style of writing provided by the MS, is truly Monitor class Enter and Exit methods, since it referred to the Monitor class that the next there is a need to pay attention:
    Pulse and PulseAll method, the two methods is to lock state is about to change the message notification queue thread to wait, but then if there is no thread waiting in the queue, then the method will wait forever until the waiting thread enters queue, that this method may result in class test deadlock situation.

    The above lock + threads (Thread and ThreadPool) = Multithreaded Programming (N%)! ?
    For this I used the formula N is 80, is now 20. There are many things which affect me, let me 80> 20, following Optex is an entry point.


public sealed class Optex : IDisposable {
   private Int32 m_Waiters = 0;
   private Semaphore m_WaiterLock = new Semaphore(0, Int32.MaxValue);

   public Optex() { }
   public void Dispose() {
      if (m_WaiterLock != null)
      { 
         m_WaiterLock.Close(); 
         m_WaiterLock = null;
      } 
   }

   public void Enter() {
      Thread.BeginCriticalRegion();
      // Add ourself to the set of threads interested in the Optex
      if (Interlocked.Increment(ref m_Waiters) == 1) {
         // If we were the first thread to show interest, we got it.
         return;
      }

      // Another thread has the Optex, we need to wait for it
      m_WaiterLock.WaitOne();
      // When WaitOne returns, this thread now has the Optex
   }

   public void Exit() {
      // Subtract ourself from the set of threads interested in the Optex
      if (Interlocked.Decrement(ref m_Waiters) > 0) {
         // Other threads are waiting, wake 1 of them
         m_WaiterLock.Release(1);
      }
      Thread.EndCriticalRegion();
   }
}
   After reading the above code, so I added the two points of recognition: 
   1, Thread.BeginCriticalRegion () and Thread.EndCriticalRegion ();         
      because this time just to read a book multithreaded programming, since the above method considered entering the critical area and exit the critical section, the critical area for the data into the area, and in the absence of exit, if the program outside the critical area of need to use it, then you have to wait for. Therefore, a critical area that has been used, why use Semaphore?
   However, MS just took the same name, to do something that is completely different from the above two methods is no concept of critical areas, it is just a set area (Begin between End), it represents a thread interrupts occur within the region or unhandled exception will affect the entire application domain.

2, the role of m_Waiters

        Enter a start in that time, to write directly on:
            m_WaiterLock.WaitOne ();

              Exit time, write: 
                   m_WaiterLock.Release (1);              
       That's it. m_Waiters What is the significance? !            
   Optimize performance, Semaphore is a kernel object, we all know as little as possible into the kernel mode, because it is very performance consuming, so use as little as possible of kernel objects. meaning m_Waiters is here, if only one thread to use when the lock object is not required to acquire and release. OK, the above things are bedding, Puwan it into the theme!

Multithreaded thinking

ThreadConcurrent.Lock namespace
{
    public class Optex Sealed: the IDisposable
    {
        /// <Summary>
        /// trivial state
        /// </ Summary>
        Private Int32 m_LockState = c_lsFree;

        /// <Summary>
        /// free state
        // / </ Summary>
        Private const Int32 c_lsFree = 0x00000000;
        
        /// <Summary>
        /// owned state
        /// </ Summary>
        Private const Int32 c_lsOwned = 0x00000001;
        
        /// <Summary>
        /// waiting thread number
        /// </ summary>
        private const Int32 c_1Waiter = 0x00000002;

        private Semaphore m_WaiterLock = new Semaphore(0, Int32.MaxValue);

        #region 构造函数

        /// <summary>
        /// 
        /// </summary>
        public Optex() { }

        #endregion

        /// <summary>
        /// 请求锁
        /// </summary>
        public void Enter()
        {
            Thread.BeginCriticalRegion();
            while (true)
            {
                Int32 ls = InterlockedOr(ref m_LockState, c_lsOwned);

                //自由状态
                IF ((LS & c_lsOwned) == c_lsFree) return;

                // increase the number of threads waiting
                IF (IfThen (REF m_LockState, LS, LS + c_1Waiter))
                {
                    m_WaiterLock.WaitOne ();
                }
            }
        }

        public void the Exit ()
        {
            // trivial release
            Int32 LS = InterlockedAnd (REF m_LockState, ~ c_lsOwned);

            // no waiting threads
            IF (LS == c_lsOwned)
            {
            }
            the else
            {
                LS = ~ & c_lsOwned;
                if (IfThen(ref m_LockState, ls & ~c_lsOwned, ls - c_1Waiter))
                {
                    m_WaiterLock.Release(1);
                }
                else
                {
                }
            }
            Thread.EndCriticalRegion();
        }

        #region 原子化操作

        /// <summary>
        /// 与操作
        /// </summary>
        /// <param name="target"></param>
        /// <param name="with"></param>
        /// <returns></returns>
        private static Int32 InterlockedAnd(ref Int32 target, Int32 with)
        {
            Int32 i, j = target;
            do
            {
                i = j;
                j = Interlocked.CompareExchange(ref target, i & with, i);
            } while (i != j);
            return j;
        }

        /// <summary>
        /// 或操作
        /// </summary>
        /// <param name="target"></param>
        /// <param name="with"></param>
        /// <returns></returns>
        private static Int32 InterlockedOr(ref Int32 target, Int32 with)
        {
            Int32 i, j = target;
            do
            {
                i = j;
                j = Interlocked.CompareExchange(ref target, i | with, i);
            } while (i != j);
            return j;
        }

        #endregion

        private static Boolean IfThen(ref Int32 val, Int32 @if, Int32 then)
        {
            return (Interlocked.CompareExchange(ref val, @then, @if) == @if);
        }

        private static Boolean IfThen(ref Int32 val, Int32 @if, Int32 then, out Int32 prevVal)
        {
            prevVal = Interlocked.CompareExchange(ref val, @then, @if);
            return (prevVal == @if);
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            if (m_WaiterLock != null)
            {
                m_WaiterLock.Close();
                m_WaiterLock = null;
            }
        }
    }
}
     For the above code, I dizzy for some time, but when I really understand, dizziness from high school to do multi-threaded programming way of thinking should have.
First began to talk about from a simple understanding,
1, atomic operations
     for InterLocked class, who knows, but with very little, but know from the code, write to shared data in multi-threaded programming, we must to achieve atomicity. As for how to do this, InterlockedAnd and InterlockedOr do a very good interpretation:
      The purpose is to ensure that the cycle While the latest target value and the value of doing the operation, if the incoming value is changed during the execution of the other threads, then is It will not exit the loop, and will re-do the operation times and take advantage of the changed value.

2, Enter and Exit understanding
     of these two methods are difficult to interpret written, with the map is the most clear.
 

Once the dizziness:
1, Why Enter method exists cycle, why is not executing the waitone ends, must m_lockState equal c_IsFree when it ends?
     Thread of execution is not entirely in accordance with a previously arranged sequence to perform, sometimes special to happen to change the thread scheduling order, so it is possible case gray part of the figure appears, then in order to solve the problems that may occur (probability is very small) circle mechanism appeared.
2. Why before WaitOne and Release, in addition to increasing and decreasing the waiters, but also need to determine whether to change the m_lockstate (enter Enter to execute the period before Waitone)?
General thinking:
 

thinking of the program:

      the benefits of doing so is to minimize the operating kernel objects, to improve performance!

      Although the complex multi-threaded programming, but I find it interesting and challenging, but also with the development of hardware, multi-threaded programming will be even more important, since it has been on the road, let us come to an end!

Reproduced in: https: //www.cnblogs.com/kevinGao/archive/2011/12/31/2323353.html

Guess you like

Origin blog.csdn.net/weixin_34168880/article/details/93052762