lock free(無鎖併發)是什麼

1、非阻塞同步(Non-blocking Synchronization)

1. 無鎖編程 / lock-free / 非阻塞同步

無鎖編程,即不使用鎖的狀況下實現多線程之間的變量同步,也就是在沒有線程被阻塞的狀況下實現變量的同步,因此也叫非阻塞同步(Non-blocking Synchronization)。html

實現非阻塞同步的方案稱爲「無鎖編程算法」( Non-blocking algorithm)。算法

lock-free是目前最多見的無鎖編程的實現級別(一共三種級別):編程

  • wait-free
  • lock-free
  • obstruction-free

 

2. 爲何要 Non-blocking sync ?

使用lock實現線程同步有不少缺點:安全

* 產生競爭時,線程被阻塞等待,沒法作到線程實時響應。數據結構

* dead lock。多線程

* live lock。併發

* 優先級翻轉。ide

* 使用不當,形成性能降低。oop

 

3. wait-free

是最理想的模式,整個操做保證每一個線程在有限步驟下完成。性能

保證系統級吞吐(system-wide throughput)以及無線程飢餓。

截止2011年,沒有多少具體的實現。即便實現了,也須要依賴於具體CPU。

 

4. lock-free

容許個別線程飢餓,但保證系統級吞吐。

確保至少有一個線程可以繼續執行。

wait-free的算法一定也是lock-free的。

 

5. obstruction-free

在任什麼時候間點,一個線程被隔離爲一個事務進行執行(其餘線程suspended),而且在有限步驟內完成。

在執行過程當中,一旦發現數據被修改(採用時間戳、版本號),則回滾。

也叫作樂觀鎖,即樂觀併發控制(OOC)。

事務的過程是:1讀取,並寫時間戳;2準備寫入,版本校驗;3校驗經過則寫入,校驗不經過,則回滾。

 

2、CAS

CAS( compare and swap) 原子操做,用來實現多線程下的變量同步。

保證了若是須要更新的地址沒有被其餘進程(線程)改動過,那麼它能夠安全的寫入。

而這也是咱們對於某個數據或者數據結構加鎖要保護的內容,保證讀寫的一致性,不出現dirty data。

 

CAS原語有三個參數:

  • 內存地址,
  • 指望值,
  • 新值。

 

算法邏輯:

  • 若是內存地址的值==指望值,表示該值未修改,此時能夠修改爲新值。
  • 不然表示修改失敗,返回false,由用戶決定後續操做。
int compare_and_swap (int* reg, int oldval, int newval) {
  ATOMIC();
  int old_reg_val = *reg;
  if (old_reg_val == oldval)
     *reg = newval;
  END_ATOMIC();
  return old_reg_val;
}

可在循環中不斷執行CAS,若是共享變量沒有改變,那麼swap,在當前環境中寫入,不然繼續do-while的Retry-Loop。

 

 

3、ABA問題

ABA問題最容易發生在lock free算法中的,地址被重用的狀況。

無鎖至關於「鎖」的粒度變小了,主要是「鎖」HEAD和TAIL這兩個關鍵資源。而不是整個數據結構。

 

thread1意圖對val=1進行操做變成2,cas(*val,1,2)。

thread1先讀取val=1;thread1被搶佔(preempted),讓thread2運行。

thread2 修改val=3,又修改回1。

thread1繼續執行,發現指望值與「原值」(其實被修改過了)相同,完成CAS操做。

 

使用CAS會形成ABA問題,特別是在使用指針操做一些併發數據結構時。

 

解決方案

ABAʹ:添加額外的標記用來指示是否被修改。

# Java demo
 
AtomicInteger atom = new AtomicInteger(1);

boolean r = atom.compareAndSet(1, 2);

 

# C# demo

int i=1;

Interlocked.Increment(ref i);
相關文章
相關標籤/搜索