在nginx中,廣泛應用了cas(compare-and-swap)操作來完成程序同步。
包括ngx_spinlock,ngx_trylock,ngx_rwlock_wlock,ngx_rwlock_rlock,ngx_shmtx_trylock,ngx_shmtx_lock等各種鎖,均由ngx_atomic_cmp_set的cas操作來實現。
cas操作作為原子操作,在linux上最低的支援版本是gcc4.1,api是
__sync_bool_compare_and_swap(lock, old, set)
在windows上,相應的api是
interlockedcompareexchange
在c++11中,進行了跨平台的擴充套件,stl的函式是
atomic_compare_exchange_weak(
在gcc4.1之前的版本,可以用函式來實現cas操作,在nginx中,給出了實現,也是cas的原理
static ngx_inline ngx_atomic_uint_t
ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old,
ngx_atomic_uint_t set)
return 0;
}
廣泛應用的cas操作,應該對應於cmpxchg 彙編指令,是一條原子操作,更確切的實現是這樣的:
static ngx_inline ngx_atomic_uint_t
ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old,
ngx_atomic_uint_t set)
既然nginx中cas是可以替代各種鎖,那用cas操作當然可以替代最簡單的mutex的互斥鎖。
替代的方法如下:
int mutex = 0;
int lock = 0;
int unlock = 1;
while (!(__sync_bool_compare_and_swap (&mutex,lock, 1) ))usleep(10000);//100000
//pthread_mutex_lock(&mutex_lock);
count++;
// pthread_mutex_unlock(&mutex_lock);
__sync_bool_compare_and_swap (&mutex, unlock, 0);
用mutex=0表示無線程用count,用mutex=1來表示有人用count。
其中usleep(10000)是我隨便寫的乙個數,來給cpu空閒的事情,在nginx中,用ngx_cpu_pause來給cpu的空閒。
其中ngx_cpu_pause的實現為
__asm__ ("pause")
這裡經測試,cas操作的效能比mutex提公升的超過10倍,而cpu的使用率基本一致,這應該是nginx高效的原因。
在nginx中,也並非完全不用mutex,仍然有用ngx_thread_mutex_lock的地方,而ngx_thread_mutex_lock的實現是mutex。
用mutex的原因,在於,需要配合條件變數來一起使用,配合ngx_thread_cond_signal,來完成執行緒和執行緒之間的任務分發。
使用mutex獲取鎖分為兩階段,第一階段在使用者態採用spinlock鎖匯流排的方式獲取一次鎖,如果成功立即返回;否則進入第二階段,呼叫系統的futex鎖去sleep,當鎖可用後被喚醒,繼續競爭鎖。這樣mutex是有進入核心態,執行緒進行睡眠。
總結一下,mutex加cond的使用場景,是不常進入,有長期等待的環境,長時間保持鎖才需要使用,比如任務的開始或結束。
執行緒頻繁切換的地方,可以完全用cas操作來進行了,當然採用cas並不是最優的方法,還需要封裝乙個spinlock才是正經的道理。
CAS無鎖機制
1 與鎖相比,使用比較交換 下文簡稱cas 會使程式看起來更加複雜一些。但由於其非阻塞性,它對死鎖問題天生免疫,並且,執行緒間的相互影響也遠遠比基於鎖的方式要小。更為重要的是,使用無鎖的方式完全沒有鎖競爭帶來的系統開銷,也沒有執行緒間頻繁排程帶來的開銷,因此,它要比基於鎖的方式擁有更優越的效能。2 ...
Nginx中accept鎖的機制
前言 nginx採用多程序的模,當乙個請求過來的時候,系統會對程序進行加鎖操作,保證只有乙個程序來接受請求。本文基於nginx 0.8.55源 並基於epoll機制分析 1.accept鎖的實現 1.1 accpet鎖是個什麼東西 提到accept鎖,就不得不提起驚群問題。所謂驚群問題,就是指的像n...
python鎖機制 python的鎖機制
鎖 lock lock 指令鎖 是可用的最低階的同步指令。lock處於鎖定狀態時,不被特定的執行緒擁有。lock包含兩種狀態 鎖定和非鎖定,以及兩個基本的方法。可以認為lock有乙個鎖定池,當執行緒請求鎖定時,將執行緒至於池中,直到獲得鎖定後出池。池中的執行緒處於狀態圖中的同步阻塞狀態。構造方法 l...