Nginx中的原子操作

2021-08-01 05:38:04 字數 1856 閱讀 5790

原子操作在系統程式設計中屬於基礎工具。nginx與其他軟體很不一樣,它幾乎把所有作業系統的功能都封裝了一遍,估計是出於程式設計一致性和可移植性的考慮。對於原子操作,nginx提供一組介面。

這裡我們只研究有gcc 4.1以上版本的情況,因為nginx對不同的情況有不同的實現,gcc應該還是比較普遍的吧

先看些基本型別

typedef 

long

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提供了哪些原子操作

#define

ngx_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前面去;

第四個介面是一條彙編指令,暫停程式執行。

其實後面兩個介面跟底層原子操作關係不是非常緊密,可能是作者覺得放在這裡最合適吧。

前面說過原子操作是基礎設施,我們有很多其他的功能要依賴它,比如實現鎖

#define

ngx_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...