原子操作在系統程式設計中屬於基礎工具。nginx與其他軟體很不一樣,它幾乎把所有作業系統的功能都封裝了一遍,估計是出於程式設計一致性和可移植性的考慮。對於原子操作,nginx提供一組介面。
這裡我們只研究有gcc 4.1以上版本的情況,因為nginx對不同的情況有不同的實現,gcc應該還是比較普遍的吧
先看些基本型別
typedeflong
ngx_atomic_int_t;
typedef unsigned
long
ngx_atomic_uint_t;
typedef volatile ngx_atomic_uint_t ngx_atomic_t;
#if(ngx_ptr_size == 8)
#define
ngx_atomic_t_len (sizeof("-9223372036854775808") - 1)
#else
#define
ngx_atomic_t_len (sizeof("-2147483648") - 1)
#endif
gcc中的long型別的長度始終是作業系統的位數,所以這一段**是可以相容64位系統的。 另外注意原子型別ngx_atomic_t一定要加上volatile標誌,如果不加的話,原子變數可能被編譯器優化到暫存器去了,就不可能利用原子操作去實現鎖的功能了。
再看nginx提供了哪些原子操作
#definengx_atomic_cmp_set(lock, old, set) __sync_bool_compare_and_swap(lock, old, set)
#define
ngx_atomic_fetch_add(value, add) __sync_fetch_and_add(value, add)
#define
ngx_memory_barrier() __sync_synchronize()
#define
ngx_cpu_pause() __asm__("pause")
第乙個介面是「如果lock指向的值等於old,那麼把lock指向的記憶體單元設為set,並返回1」,其他情況則返回0;
第二個介面是「將value指向的值增加add,返回增加以前的值」;
第三個介面的功能也有點兒詭異,假如你在**中放上這個函式,那麼編譯器就不會為了優化而打亂這個函式前後的指令,這也是為什麼它取名叫barrier,相當於乙個屏障,阻止編譯器把後面的指令搬到barrier前面去;
第四個介面是一條彙編指令,暫停程式執行。
其實後面兩個介面跟底層原子操作關係不是非常緊密,可能是作者覺得放在這裡最合適吧。
前面說過原子操作是基礎設施,我們有很多其他的功能要依賴它,比如實現鎖
#definengx_trylock(lock) (*lock==0 && ngx_atomic_cmp_set(lock, 0, 1))
#define
ngx_unlock(lock) *(lock) = 0
ngx_trylock顧名思義是嘗試著去加鎖,能加則加,不能則向呼叫者報告失敗,1代表成功,0代表失敗。不過我對這個實現有點兒疑問,直接使用ngx_atomic_cmp_set就可以了啊,為什麼還要在前面加乙個玩意兒,難道是為了效能?還有一點使用者要注意,lock一定要是ngx_atomic_t型別的,這是個巨集,是不會做型別檢查的。
ngx_unlock毋庸贅言了吧,就是解鎖的。
原子性,原子操作
舉個例子 a想要從自己的帳戶中轉1000塊錢到b的帳戶裡。那個從a開始轉帳,到轉帳結束的這乙個過程,稱之為乙個事務。在這個事務裡,要做如下操作 從a的帳戶中減去1000塊錢。如果a的帳戶原來有3000塊錢,現在就變成2000塊錢了。在b的帳戶裡加1000塊錢。如果b的帳戶如果原來有2000塊錢,現在...
boost庫中的原子操作
boost庫這中有有關多執行緒的內容,粗略看書,似乎比c 11 的多執行緒好一丟丟。做個讀書筆記,以後忘了可以參考。原子操作 atomic 需要包含標頭檔案 include要用這個標頭檔案,boost庫是需要編譯的,最好是root許可權下編譯,要不會出錯。boost atomica 10 定義a為原...
原子變數與原子操作
1.原子操作的速度要快於臨界區,event,互斥量,如果多個執行緒同時寫乙個變數時,最方便的就是原子操作。原子操作函式,解決多執行緒安全 2.原子變數也是為了解決執行緒衝突問題,如果兩個執行緒同時訪問同乙個變數,乙個執行緒改變了這個變數,另乙個執行緒就會出現一些bug。3.release和debug...