UMA架構與NUMA架構下的自旋鎖(CLH鎖與MCS鎖)

關於自旋鎖

咱們知道自旋鎖是實現同步的一種方案,它是一種非阻塞鎖。它與常規鎖的主要區別就在於獲取鎖失敗後的處理方式不一樣,常規鎖會將線程阻塞並在適當時喚醒它。而自旋鎖的核心機制就在自旋兩個字,即用自旋操做來替代阻塞操做。某一線程嘗試獲取某個鎖時,若是該鎖已經被另外一個線程佔用的話,則此線程將不斷循環檢查該鎖是否被釋放,而不是讓此線程掛起或睡眠。一旦另一個線程釋放該鎖後,此線程便能得到該鎖。自旋是一種忙等待狀態,過程當中會一直消耗CPU的時間片。算法

自旋鎖

UMA架構

由於在分析CLH鎖與MCS鎖的缺點時會涉及處理器架構問題,因此在介紹每種自旋鎖以前咱們須要先了解兩種處理器架構:UMA架構和NUMA架構。在多處理器系統中,根據內存的共享方式能夠分爲UMA(Uniform Memory Access)和NUMA(Non-uniform Memory Access),即統一內存訪問和非統一內存訪問。緩存

UMA架構的性質就是每一個CPU核訪問主存儲的時間都是同樣的。下面看基於總線的UMA架構,一共有4個CPU處理器,它們都直接與總線鏈接,經過總線進行通訊。從這個結構中能夠看到,每一個CPU都沒有區別,它們平等地訪問主存儲。訪問主存儲所需的時間都是同樣的,即爲統一內存訪問。數據結構

UMA架構

當某個CPU想要進行讀寫操做時,它首先會檢查總線是否空閒,只有在空閒狀態下才能容許其與主存儲進行通訊,不然它將等待直到總線空閒。爲了優化這個問題,在每一個CPU的內部引入緩存。這樣一來,CPU的讀操做就可以在本地的緩存中進行。但這時咱們須要考慮CPU中緩存與主存的數據一致性問題,不然可能會引發髒數據問題。多線程

UMA架構2

NUMA架構

與UMA架構相反,NUMA架構中並不是每一個CPU對主存儲的訪問時間都相同的,NUMA架構中CPU能訪問全部主存儲。經過下圖能夠看到CPU若是經過本地總線來訪問相應的本地主存儲的話,則訪問時間較短,但若是訪問的是非本地主存儲(遠程主存)則時間將很長,也就是CPU訪問本地主存和訪問遠程主存的速度不相同。NUMA架構的優勢就在於,它具備優秀的可擴展性,可以實現超過百個CPU的組合。架構

NUMA架構

CLH鎖

Craig、Landin、Hagersten三我的發明了CLH鎖。其核心思想是:經過必定手段將全部線程對某一共享變量的輪詢競爭轉化爲一個線程隊列,且隊列中的線程各自輪詢本身的本地變量。機器學習

這個轉化過程有兩個要點:一是應該構建怎樣的隊列以及如何構建隊列?爲了保證公平性,咱們構建的將是一個FIFO隊列。構建的時候主要經過移動尾部節點tail來實現隊列的排隊,每一個想獲取鎖的線程建立一個新節點並經過CAS原子操做將新節點賦給tail,而後讓當前線程輪詢前一節點的某個狀態位。如圖能夠清晰看到隊列結構及自旋操做,這樣就成功構建了線程排隊隊列。二是如何釋放隊列?執行完線程後只需將當前線程對應的節點狀態位置爲解鎖狀態便可,因爲下一節點一直在輪詢,因此可獲取到鎖。分佈式

CLH鎖

因此,CLH鎖的核心思想是將衆多線程長時間對某資源的競爭,經過有序化這些線程將其轉化爲只需對本地變量檢測。而惟一存在競爭的地方就是在入隊列以前對尾節點tail的競爭,但此時競爭的線程數量已經少了不少了。比起全部線程直接對某資源競爭的輪詢次數也減小了不少,這也大大節省了CPU緩存同步的消耗,從而大大提高系統性能。性能

CLH鎖已經解決了大量線程同時操做同一個變量而帶來的同步問題,但它的自旋的對象是前驅節點。在NUMA架構下可能會存在性能問題,由於若是前驅節點和當前節點再也不同一個本地主存儲的話則訪問時間會很長,這就會致使性能受影響。學習

MCS鎖

MCS鎖由John Mellor-Crummey和Michael Scott兩人發明,它的出現旨在解決CLH鎖存在的問題。它也是基於FIFO隊列,與CLH鎖類似,不一樣的地方在於輪詢的對象不一樣。MCS鎖中線程只對本地變量自旋,而前驅節點則負責通知其結束自旋操做。這樣的話就減小了CPU緩存與主存儲之間的沒必要要的同步操做,減小了同步帶來的性能損耗。優化

以下圖,每一個線程對應着隊列中的一個節點。節點內有一個spin變量,表示是否須要旋轉。一旦前驅節點使用完鎖後,便修改後繼節點的spin變量,通知其沒必要繼續作自旋操做,已成功獲取鎖。

MCS鎖

專一於人工智能、讀書與感想、聊聊數學、計算機科學、分佈式、機器學習、深度學習、天然語言處理、算法與數據結構、Java深度、Tomcat內核等。

相關文章
相關標籤/搜索