(有半年沒有寫部落格了,時間飛逝呀。。。。 :o )
這裡簡單介紹一下無鎖併發程式設計。
現在cpu的核越來越多,多執行緒、併發程式設計已經成為趨勢。一涉及併發,同步是繞不開的話題。一般的方法是使用mutex、旋轉鎖、條件變數等系統提供的方法來進行同步。(乙個問題,mutex和自旋鎖的區別?)如果併發不太大,qps是數百時,這些方法還沒有問題,但是當qps增加到數千時,這些同步方法的開銷就太大了,會對系統產生不小的開銷,影響程式的效能。怎麼辦?
一種方法是先建立一堆執行緒池,然後將query計算後(比如取模),傳給相應的執行緒處理,這樣即使使用傳統的同步方法,還是可以降低同步的開銷。然而對於全域性唯一的資源,還是不能降低同步的開銷。這樣,就引出了無鎖併發的概念。
無鎖併發(lock-free),就是不使用鎖來進行同步,那就要知道cas(compare&set或者compare&swap)的概念。其實cas很簡單,就是取出資源或者版本號後,再進行操作前,再進行比較,看期間資源或版本號有沒有改變,如果沒有,則表明沒有其他程式修改過,可以直接修改。如果當前的資料和之前的資料不一樣,則表明期間資源被修改過,則之前的資源位址後者版本號已經失效,需要重新獲取,之後再次比較和操作。
要進行cas,要了解[color=darkred]gcc內建[/color]提供的一系列原子操作的函式:
type __sync_fetch_and_add (type *ptr, type value, ...)
type __sync_fetch_and_sub (type *ptr, type value, ...)
type __sync_fetch_and_or (type *ptr, type value, ...)
type __sync_fetch_and_and (type *ptr, type value, ...)
type __sync_fetch_and_xor (type *ptr, type value, ...)
type __sync_fetch_and_nand (type *ptr, type value, ...)
type __sync_add_and_fetch (type *ptr, type value, ...)
type __sync_sub_and_fetch (type *ptr, type value, ...)
type __sync_or_and_fetch (type *ptr, type value, ...)
type __sync_and_and_fetch (type *ptr, type value, ...)
type __sync_xor_and_fetch (type *ptr, type value, ...)
type __sync_nand_and_fetch (type *ptr, type value, ...)
這兩組函式的區別在於第一組返回更新前的值,第二組返回更新後的值。
type可以是1,2,4或8位元組長度的int型別,即:
int8_t / uint8_t
int16_t / uint16_t
int32_t / uint32_t
int64_t / uint64_t
後面的可擴充套件引數(...)用來指出哪些變數需要memory barrier,因為目前gcc實現的是full barrier(類似於linux kernel 中的mb(),表示這個操作之前的所有記憶體操作不會被重排序到這個操作之後),所以可以略掉這個引數。
bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, ...)
type __sync_val_compare_and_swap (type *ptr, type oldval type newval, ...)
這兩個函式提供原子的比較和交換,如果*ptr == oldval,就將newval寫入*ptr,
第乙個函式在相等並寫入的情況下返回true.
第二個函式在返回操作之前的值。
__sync_synchronize (...)
發出乙個full barrier.
這樣,就可以利用這些內建的函式,開發乙個無鎖的stack:
template
class stack
} node;
node *top;
public:
stack( ) : top(0)
void push(const t& data);
t pop( ) throw (…);
};void stack::push(const t& data) }}
t stack::pop( ) }}
嗯,基本就是這麼簡單,當然還有一些複雜的場景需要探索,要在使用中摸索。
其實想一想,cas最終還是用到了「鎖」,不過這個鎖是程式語言控制的最小的同步鎖,所以顆粒是最小的,對系統的開銷也是最小的。
後記:無鎖程式設計中乙個很大的問題是aba問題(變數中間被修改後又復原了),可能造成程式的隱患,所以無鎖程式設計侷限性還是很大的。
參考:[url]
[url]
簡談網路程式設計
網路程式設計的本質是兩個裝置之間的資料交換。乙個裝置中的資料傳送給兩外乙個裝置,然後接受另外乙個裝置反饋的資料。現在的網路程式設計基本上都是基於請求 響應方式的,也就是乙個裝置傳送請求資料給另外乙個,然後接收另乙個裝置的反饋。傳送第一次請求的程式,被稱作客戶端 client 等待其他程式連線的程式被...
無鎖程式設計 大綱
鎖定被迫交出時間片。鎖定意味著阻塞,多個執行緒 程序 排隊獲取資源,無法充分發揮系統效能。鎖定的阻塞無法通過fd進行通知,對效能有進一步的影響 理想的伺服器模型是全域性一處阻塞統一等待訊息 一些鎖限制了必須使用執行緒的方式進行開發,而執行緒無法充分利用系統的記憶體。pthread庫在特殊情況下可能產...
併發無鎖佇列學習(一)
1 概述 佇列在計算機中非常重要的一種 資料結構 尤其在 作業系統 中。佇列典型的特徵是先進先出 fifo 符合流水線業務流程。在程序間通訊 網路通訊之間經常採用佇列做快取,緩解資料處理壓力。結合自己在工作中遇到的佇列問題,總結一下對不同場景下的佇列實現。根據操作佇列的場景分為 單生產者 單消費者 ...