atomic_inc(&v)原子操作簡述


atomic_inc(&v)對變量v用鎖定總線的單指令進行不可分解的"原子"級增量操作,避免v的值由於中斷或多處理器同時操作造成不確定狀態。

 

原子操作

  所謂原子操作,就是該操作絕不會在執行完畢前被任何其他任務或事件打斷,也就說,它的最小的執行單位,不可能有比它更小的執行單位,因此這里的原子實際是使用了物理學里的物質微粒的概念。

  原子操作需要硬件的支持,因此是架構相關的,其API和原子類型的定義都定義在內核源碼樹的include/asm/atomic.h文件中,它們都使用匯編語言實現,因為C語言並不能實現這樣的操作。

  原子操作主要用於實現資源計數,很多引用計數(refcnt)就是通過原子操作實現的。原子類型定義如下:

typedef struct { volatile int counter; } atomic_t;

  volatile修飾字段告訴gcc不要對該類型的數據做優化處理,對它的訪問都是對內存的訪問,而不是對寄存器的訪問。 

  原子操作API包括: 

atomic_read(atomic_t * v);

  該函數對原子類型的變量進行原子讀操作,它返回原子類型的變量v的值。 

 

atomic_set(atomic_t * v, int i);

  該函數設置原子類型的變量v的值為i。 

 

void atomic_add(int i, atomic_t *v);

  該函數給原子類型的變量v增加值i。 

atomic_sub(int i, atomic_t *v);

  該函數從原子類型的變量v中減去i。 

 

int atomic_sub_and_test(int i, atomic_t *v);

  該函數從原子類型的變量v中減去i,並判斷結果是否為0,如果為0,返回真,否則返回假。 

 

void atomic_inc(atomic_t *v);

  該函數對原子類型變量v原子地增加1。 

 

void atomic_dec(atomic_t *v);

  該函數對原子類型的變量v原子地減1。 

 

int atomic_dec_and_test(atomic_t *v);

  該函數對原子類型的變量v原子地減1,並判斷結果是否為0,如果為0,返回真,否則返回假。 

 

int atomic_inc_and_test(atomic_t *v);

  該函數對原子類型的變量v原子地增加1,並判斷結果是否為0,如果為0,返回真,否則返回假。 

 

int atomic_add_negative(int i, atomic_t *v);

  該函數對原子類型的變量v原子地增加I,並判斷結果是否為負數,如果是,返回真,否則返回假。 

 

int atomic_add_return(int i, atomic_t *v);

  該函數對原子類型的變量v原子地增加i,並且返回指向v的指針。 

 

int atomic_sub_return(int i, atomic_t *v);

  該函數從原子類型的變量v中減去i,並且返回指向v的指針。 

 

int atomic_inc_return(atomic_t * v);

  該函數對原子類型的變量v原子地增加1並且返回指向v的指針。 

 

int atomic_dec_return(atomic_t * v);

   該函數對原子類型的變量v原子地減1並且返回指向v的指針。 


  原子操作通常用於實現資源的引用計數,在TCP/IP協議棧的IP碎片處理中,就使用了引用計數,碎片隊列結構struct ipq描述了一個IP碎片,字段refcnt就是引用計數器,它的類型為atomic_t,當創建IP碎片時(在函數ip_frag_create中),使用atomic_set函數把它設置為1,當引用該IP碎片時,就使用函數atomic_inc把引用計數加1。 
  當不需要引用該IP碎片時,就使用函數ipq_put來釋放該IP碎片,ipq_put使用函數atomic_dec_and_test把引用計數減1並判斷引用計數是否為0,如果是就釋放IP碎片。函數ipq_kill把IP碎片從ipq隊列中刪除,並把該刪除的IP碎片的引用計數減1(通過使用函數atomic_dec實現)。

 

 ARMv6_Architecture.pdf    解釋如下   

• LDREX{} , []
  This performs a load, then sets a monitor to “watch” the address
• STREX {} , , []
  This performs a store and returns “success” in Rd if no intervening access
detected by the monitor.

 

X86 用LOCK 指令實現

ARM代碼如下,  ldrex :

static inline int atomic_add_return(int i, atomic_t *v)
{
        unsigned long tmp;
        int result;

        __asm__ __volatile__("@ atomic_add_return/n"
"1:     ldrex   %0, [%2]/n"
"       add     %0, %0, %3/n"
"       strex   %1, %0, [%2]/n"
"       teq     %1, #0/n"
"       bne     1b"
        : "=&r" (result), "=&r" (tmp)
        : "r" (&v->counter), "Ir" (i)
        : "cc");

        return result;

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM