国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

多線程中的鎖系統(四)-談談自旋鎖

2019-11-17 02:36:52
字體:
來源:轉載
供稿:網友

多線程中的鎖系統(四)-談談自旋鎖

2015-01-24 20:41 by 蘑菇先生, ... 閱讀, ... 評論, 收藏, 編輯

閱讀目錄:

  1. 基礎
  2. 自旋鎖示例
  3. SpinLock
  4. 繼續SpinLock
  5. 總結

基礎

內核鎖:基于內核對象構造的鎖機制,就是通常說的內核構造模式。用戶模式構造和內核模式構造

優點:cpu利用最大化。它發現資源被鎖住,請求就排隊等候。線程切換到別處干活,直到接受到可用信號,線程再切回來繼續處理請求。

缺點:托管代碼->用戶模式代碼->內核代碼損耗、線程上下文切換損耗。

在鎖的時間比較短時,系統頻繁忙于休眠、切換,是個很大的性能損耗。

自旋鎖:原子操作+自循環。通常說的用戶構造模式。 線程不休眠,一直循環嘗試對資源訪問,直到可用。

優點:完美解決內核鎖的缺點。

缺點:長時間一直循環會導致cpu的白白浪費,高并發競爭下、CPU的消耗特別嚴重。

混合鎖:內核鎖+自旋鎖。混合鎖是先自旋鎖一段時間或自旋多少次,再轉成內核鎖。

優點:內核鎖和自旋鎖的折中方案,利用前二者優點,避免出現極端情況(自旋時間過長,內核鎖時間過短)。

缺點: 自旋多少時間、自旋多少次,這些策略很難把控。

操作系統及net框架層,這塊算法策略做的已經非常優了,有些API函數也提供了時間及次數可配置項,讓使用者根據需求自行判斷。

自旋鎖示例

來看下我們自己簡單實現的自旋鎖:

        int signal = 0;            var li = new List<int>();            Parallel.For(0, 1000 * 10000, r =>            {                while (Interlocked.Exchange(ref signal, 1) != 0)//加自旋鎖                {                    //黑魔法                }                li.Add(r);                Interlocked.Exchange(ref signal, 0);  //釋放鎖            });            Console.WriteLine(li.Count);            //輸出:10000000

上面就是自旋鎖:Interlocked.Exchange+while

1:定義signal 0可用,1不可用。

2:Parallel模擬并發競爭,原子更改signal狀態。 后續線程自旋訪問signal,是否可用。

3:A線程使用完后,更改signal為0。 剩余線程競爭訪問資源,B線程勝利后,更改signal為1,失敗線程繼續自旋,直到可用。

SpinLock

SpinLock是net4.0后Net提供的自旋鎖類庫,內部做了優化。

簡單看下實例:

  var li = new List<int>();            var sl = new SpinLock();            Parallel.For(0, 1000 * 10000, r =>            {                bool gotLock = false;     //釋放成功                sl.Enter(ref gotLock);    //進入鎖                li.Add(r);                if (gotLock) sl.Exit();  //釋放            });            Console.WriteLine(li.Count);            //輸出:10000000

繼續SpinLock

new SpinLock(false) 這個構造函數主要用來檢查死鎖用,true是開啟。

在開啟狀態下,一旦發生死鎖會直接拋異常的。

SpinLock實現的部分源碼

  public void Enter(ref bool lockTaken)         {            if (lockTaken)             {                 lockTaken = false;                throw new System.ArgumentException(Environment.GetResourceString("SpinLock_TryReliableEnter_ArgumentException"));             }            // Fast path to acquire the lock if the lock is released            // If the thread tracking enabled set the new owner to the current thread id             // Id not, set the anonymous bit lock            int observedOwner = m_owner;             int newOwner = 0;             bool threadTrackingEnabled = (m_owner & LOCK_ID_DISABLE_MASK) == 0;            if (threadTrackingEnabled)             {                if (observedOwner == LOCK_UNOWNED)                    newOwner = Thread.CurrentThread.ManagedThreadId;            }             else if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED)            {                 newOwner = observedOwner | LOCK_ANONYMOUS_OWNED; // set the lock bit             }            if (newOwner != 0)             {#if !FEATURE_CORECLR                Thread.BeginCriticalRegion();#endif #if PFX_LEGACY_3_5                 if (Interlocked.CompareExchange(ref m_owner, newOwner, observedOwner) == observedOwner)                 {                    lockTaken = true;                     return;                }#else                if (Interlocked.CompareExchange(ref m_owner, newOwner, observedOwner, ref lockTaken) == observedOwner)                 {                    // Fast path succeeded                     return;                 }#endif #if !FEATURE_CORECLR                Thread.EndCriticalRegion();#endif            }             //Fast path failed, try slow path            ContinueTryEnter(Timeout.Infinite, ref lockTaken);         } PRivate void ContinueTryEnter(int millisecondsTimeout, ref bool lockTaken)        {             long startTicks = 0;             if (millisecondsTimeout != Timeout.Infinite && millisecondsTimeout != 0)            {                 startTicks = DateTime.UtcNow.Ticks;            }#if !FEATURE_PAL && !FEATURE_CORECLR   // PAL doesn't support  eventing, and we don't compile CDS providers for Coreclr             if (CdsSyncEtwBCLProvider.Log.IsEnabled())            {                 CdsSyncEtwBCLProvider.Log.SpinLock_FastPathFailed(m_owner);             }#endif             if (IsThreadOwnerTrackingEnabled)            {                // Slow path for enabled thread tracking mode                 ContinueTryEnterWithThreadTracking(millisecondsTimeout, startTicks, ref lockTaken);                return;             }             // then thread tracking is disabled             // In this case there are three ways to acquire the lock            // 1- the first way the thread either tries to get the lock if it's free or updates the waiters, if the turn >= the processors count then go to 3 else go to 2            // 2- In this step the waiter threads spins and tries to acquire the lock, the number of spin iterations and spin count is dependent on the thread turn            // the late the thread arrives the more it spins and less frequent it check the lock avilability             // Also the spins count is increaes each iteration            // If the spins iterations finished and failed to acquire the lock, go to step 3             // 3- This is the yielding step, there are two ways of yielding Thread.Yield and Sleep(1)             // If the timeout is expired in after step 1, we need to decrement the waiters count before returning             int observedOwner;            //***Step 1, take the lock or update the waiters             // try to acquire the lock directly if possoble or update the waiters count            SpinWait spinner = new SpinWait();             while (true)             {                observedOwner = m_owner;                 if ((observedOwner & LOCK_ANONYMOUS_OWNED) == LOCK_UNOWNED)                {#if !FEATURE_CORECLR                    Thread.BeginCriticalRegion(); #endif #if PFX_LEGACY_3_5                     if (Interlocked.CompareExchange(ref m_owner, observedOwner | 1, observedOwner) == observedOwner)                    {                         lockTaken = true;                        return;                    }#else                     if (Interlocked.CompareExchange(ref m_owner, observedOwner | 1, observedOwner, ref lockTaken) == observedOwner)                    {                         return;                     }#endif #if !FEATURE_CORECLR                    Thread.EndCriticalRegion();#endif                 }                else //failed to acquire the lock,then try to update the waiters. If the waiters count reached the maximum, jsut break the loop to avoid overflow                     if ((observedOwner & WAITERS_MASK) ==  MAXIMUM_WAITERS || Interlocked.CompareExchange(ref m_owner, observedOwner + 2, observedOwner) == observedOwner)                         break;                 spinner.SpinOnce();            }            // Check the timeout.             if (millisecondsTimeout == 0 ||                (millisecondsTimeout != Timeout.Infinite &&                 TimeoutExpired(startTicks, millisecondsTimeout)))             {                DecrementWaiters();                 return;            }            //***Step 2. Spinning             //lock acquired failed and waiters updated            int turn = ((observedOwner + 2) & WAITERS_MASK) / 2;             int processorCount = PlatformHelper.ProcessorCount;             if (turn < processorCount)            {                 int processFactor = 1;                for (int i = 1; i <= turn * SPINNING_FACTOR; i++)                {                    Thread.SpinWai
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 宁远县| 满洲里市| 长葛市| 远安县| 辽中县| 平江县| 卢氏县| 通化县| 新安县| 东源县| 宜州市| 敖汉旗| 普安县| 屏南县| 怀宁县| 福建省| 香河县| 九台市| 五河县| 遵义市| 西林县| 尚义县| 新营市| 靖江市| 桐城市| 建阳市| 永顺县| 车险| 工布江达县| 黎平县| 越西县| 永康市| 昆明市| 峨山| 微博| 新民市| 德惠市| 余姚市| 喀喇| 蚌埠市| 丹凤县|