linux 原子整數操作詳解

2021-06-14 15:31:16 字數 4933 閱讀 7046

原子操作,顧名思義,就是說像原子一樣不可再細分不可被中途打斷。乙個操作是原子操作,意思就是說這個操作是以原子的方式被執行,要一口氣執行完,執行過程不能夠被os的其他行為打斷,是乙個整體的過程,在其執行過程中,os的其它行為是插不進來的。

在linux中提供了兩種形式的原子操作:

一種是對整數進行的操作

一種是對單獨的位進行操作

在linux中有乙個專門的atomic_t型別(乙個24位原子訪問計數器)和一些對atomic型別變數進行相應操作的的函式

其atomic_t原型如下:

typedef struct atomic_t;

它是乙個只含有乙個volatile型別的成員變數的結構體;因此編譯器不對相應的值進行訪問優化(因為是volatile型別的)。

原子整數操作的使用:

常見的用途是計數器,因為計數器是乙個很簡單的操作,所以無需複雜的鎖機制;

能使用原子操作的地方,盡量不使用複雜的鎖機制;

對atomic_t型別的變數的使用方法以及對其所能進行的操作:

下面是相應的函式及其原型:

******

在其函式的實現體中,有乙個lock_prefix巨集定義,如果選了config_smp,就會定義這麼乙個巨集,與smp相關的一些設定,否則lock_prefix的定義就為空;

******

//原子的讀取atomic_t變數的值,v是這個變數的位址

#define atomic_read(v)        ((v)->counter)

//原子的設定atomic_t變數的值,v是這個變數的位址,i要設定的新值;

#define atomic_set(v,i)        (((v)->counter) = (i))

//原子的增加atomic_t變數的值,i是要增加的數值,v是這個變數的位址

static __inline__ void atomic_add(int i, atomic_t *v)

//原子的減少atomic_t變數的值,i是要減少的數值,v是這個變數的位址;

static __inline__ void atomic_sub(int i, atomic_t *v)

//原子的對atomic_t變數的值進行減少i的操作,並且檢測其結果是否為0;若為0,返回true,否則,返回false;

//i是要減少的數值,v是這個變數的位址;

static __inline__ int atomic_sub_and_test(int i, atomic_t *v)

//原子的對atomic_t變數的值進行加1的操作,v是這個變數的位址;

static __inline__ void atomic_inc(atomic_t *v)

//原子的對atomic_t變數的值進行減1的操作,v是這個變數的位址;

static __inline__ void atomic_dec(atomic_t *v)

//原子的對atomic_t變數的值進行減少1的操作,並且檢測其結果是否為0;若為0,返回true,否則,返回false;

//v是這個變數的位址;

static __inline__ int atomic_dec_and_test(atomic_t *v)

//原子的對atomic_t變數的值進行加1的操作,並且檢測其結果是否為0;若為0,返回true,否則,返回false;

//v是這個變數的位址;

static __inline__ int atomic_inc_and_test(atomic_t *v)

//原子的對atomic_t變數的值進行加i的操作,並且檢測其結果是否為負;若為負,返回true,否則,返回false;

//i是要增加的數值,v是這個變數的位址;

static __inline__ int atomic_add_negative(int i, atomic_t *v)

//原子的對atomic_t變數的值進行加i的操作,並且將所得結果返回;

//i是要增加的數值,v是這個變數的位址;

static __inline__ int atomic_add_return(int i, atomic_t *v)

//原子的對atomic_t變數的值進行減i的操作,並且將所得結果返回;

//i是要減少的數值,v是這個變數的位址;

static __inline__ int atomic_sub_return(int i, atomic_t *v)

//原子的比較old與v是否相等,若相等,則把new的值寫入到v中,並且返回old的值;

#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))

//原子的比較

#define atomic_xchg(v, new) (xchg(&((v)->counter), new))

/*** atomic_add_unless - add unless the number is a given value

* @v: pointer of type atomic_t

* @a: the amount to add to v...

* @u: ...unless v is equal to u.

** atomically adds @a to @v, so long as it was not @u.

* returns non-zero if @v was not @u, and zero otherwise.

*///原子的對atomic_t變數的值進行加a的操作,直到v等於u,如果v與u不等,返回非零值;否則返回0;

//a是要增加的數值,v是這個變數的位址,u是要比較的值;

#define atomic_add_unless(v, a, u)                \

(                            \

c != (u);                        \

})#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)

#define atomic_inc_return(v)  (atomic_add_return(1,v))

#define atomic_dec_return(v)  (atomic_sub_return(1,v))

//掩碼

/* these are x86-specific, used by some header files */

#define atomic_clear_mask(mask, addr) \

__asm__ __volatile__(lock_prefix "andl %0,%1" \

: : "r" (~(mask)),"m" (*addr) : "memory")

#define atomic_set_mask(mask, addr) \

__asm__ __volatile__(lock_prefix "orl %0,%1" \

: : "r" (mask),"m" (*(addr)) : "memory")

下面舉例說明原子操作的用法:

定義乙個atomic_c型別的資料很簡單,還可以定義時給它設定初值:

(1) atomic_t u;                     /*定義 u*/

(2) atomic_t v = atomic_init(0)     /*定義 v 並把它初始化為0*/

對其操作:

(1) atomic_set(&v,4)                /* v = 4 ( 原子地)*/

(2) atomic_add(2,&v)                /* v = v + 2 = 6 (原子地) */

(3) atomic_inc(&v)                   /* v = v + 1 =7(原子地)*/

如果需要將atomic_t轉換成int型,可以使用atomic_read()來完成:

printk(「%d\n」,atomic_read(&v));    /* 會列印7*/

原子整數操作最常見的用途就是實現計數器。使用複雜的鎖機制來保護乙個單純的計數器是很笨拙的,所以,開發者最好使用atomic_inc()和atomic_dec()這兩個相對來說輕便一點的操作。

還可以用原子整數操作原子地執行乙個操作並檢查結果。乙個常見的例子是原子的減操作和檢查。

int atomic_dec_and_test(atomic_t *v)

這個函式讓給定的原子變數減1,如果結果為0,就返回1;否則返回0

原子位操作

操作函式的引數是乙個指標和乙個位號

第0位是給定位址的最低有效位

原子位操作中沒有特殊的資料型別

例如:set_bit(0, &word);

如:標誌暫存器eflsgs的系統標誌,用於控制i/o訪問,可遮蔽硬體中斷。共32位,不同的位代表不同的資訊,對其中資訊改變都是通過位操作實現的

原子操作中的位操作部分函式如下:

void set_bit(int nr, void *addr)        原子設定addr所指的第nr位

void clear_bit(int nr, void *addr)      原子的清空所指物件的第nr位

void change_bit(nr, void *addr)         原子的翻轉addr所指的第nr位

int test_bit(nr, void *addr)            原子的返回addr位所指物件nr位

int test_and_set_bit(nr, void *addr)    原子設定addr所指物件的第nr位,並返回原先的值

int test_and_clear_bit(nr, void *addr)  原子清空addr所指物件的第nr位,並返回原先的值

int test_and_change_bit(nr, void *addr)  原子翻轉addr所指物件的第nr位,並返回原先的值

原子操作詳解

原子操作 原子操作是指不會被執行緒排程機制打斷的操作 這種操作一旦開始,就一直執行到結束,中間不會被其他程序打斷。它是其他核心同步方法的基石。編寫 時能使用原子操作的,就盡量不要用加鎖機制,因為原子操作給系統帶來的開銷小。一 原子整數操作 1 型別的定義 針對整數的原子操作只能對atomic t型別...

Linux 原子操作

所謂原子操作,就是該操作絕不會在執行完畢前被任何其他任務或事件打斷,也就說,它的最小的執行單位,不可能有比它更小的執行單位,因此這裡 的原子實際是使用了物理學裡的物質微粒的概念。原子操作需要硬體的支援,因此是架構相關的,其api和原子型別的定義都定義在核心原始碼樹的include asm atomi...

linux原子操作

原子操作指的是在執行過程中不會被別的 路徑所中斷的操作,下面列出原子操作相關的函式 1.void atomic set atomic t v,int i 設定原子變數的值為i 2.atomic t v atomic init 0 定義原子變數v並初始化為0 3.atomic read atomic ...