linux内核中的原子操作

在linux中有一个专门的atomic_t类型(一个24位原子访问计数器)和一些对atomic类型变量进行相应操作的的函数。
其atomic_t原型如下:
 typedef struct {
 volatile int counter;
} atomic_t;
它是一个只含有一个volatile类型的成员变量的结构体;因此编译器不对相应的值进行访问优化(因为是volatile类型的)。

原子整数操作的使用:
    常见的用途是计数器,因为计数器是一个很简单的操作,所以无需复杂的锁机制;能使用原子操作的地方,尽量不使用复杂的锁机制;

1.整型原子操作

  1.1 设置源自变量的值

      void atomic_set(atomic_t *v,int i);  //设置原子变量的的值为i

      atomic_t v = ATOMIC_INIT(0);         //定义原子变量,并将其初始化为0

  1.2 获取元原子变量的值

      atomic_read(atomic_t *v);            //返回原子变量的值

      这是一个宏定义:#define  atomic_read(v)   (*(volatile int)&(v)->counter)


代码实现:

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

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


  1.3 原子变量加减

      void atomic_add(int i,atomic_t *v);   //原子变量增加i

      void atomic_sub(int i,atomic_t *v);   //原子变量减少i


各CPU通过原子操作指令实现。如果CPU不支持,用锁中断方式实现:

//atomic_add_return

 raw_local_irq_save(flags);

 val = v->counter;

 v->counter = val += i;

 raw_local_irq_restore(flags);


  1.4 原子变量自增、自减

      void atomic_inc(atomic_t *v);

      void atomic_dec(atomic_t *v);

  1.5 操作并测试

      int atomic_int_and_test(atomic_t *v);

      int atomic_dec_and_test(atomic_t *v);

      int atomic_sub_and_test(int i,atomic_t *v);

      以上操作后测试其是否为0,为0则返回true,否则返回false。

  1.6 操作并返回

      int atomic_add_and_return(int i,atomic_t *v);

      int atomic_sub_and_return(int i,atomic_t *v);

      int atomic_dec_and_return(atomic_t *v);

      int atomic_inc_and_return(atomic_t *v);

      以上操作后返回新的值。


代码实现:

#define atomic_inc(v) atomic_add(1, v)

#define atomic_dec(v) atomic_sub(1, v)

#define atomic_inc_and_test(v) (atomic_add_return(1, v) == 0) 

#define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0)

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

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

#define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0)


2. 位原子操作 

   2.1 设置位

      void  set_bit(nr,void *addr);   //设置addr地址的第nr位为1

   2.2 清除位

     void  clear_bit(nr, void *addr); //设置addr地址的第nr位为0

   2.3 改变位

     void change_bit(nr, void *addr); //反置addr的第nr位

   2.4 测试位

     void test_bit(nr,void *addr);    //返回addr的nr位

   2.5 测试并操作位

     void  test_and_set_bit(nr, void *addr);   //设置addr所指对象的第nr位,并返回原先的值

     void  test_and_clear_bit(nr,void *addr);  //清空addr所指对象的第nr位,并返回原先的值

     void  test_and_change_bit(nr,void *addr); //翻转addr所指对象的第nr位,并返回原先的值


#define set_bit(nr,p) ATOMIC_BITOP_LE(set_bit,nr,p)

#define clear_bit(nr,p) ATOMIC_BITOP_LE(clear_bit,nr,p)

#define change_bit(nr,p) ATOMIC_BITOP_LE(change_bit,nr,p)

#define test_and_set_bit(nr,p) ATOMIC_BITOP_LE(test_and_set_bit,nr,p)

#define test_and_clear_bit(nr,p) ATOMIC_BITOP_LE(test_and_clear_bit,nr,p)

#define test_and_change_bit(nr,p) ATOMIC_BITOP_LE(test_and_change_bit,nr,p)


#define ATOMIC_BITOP_LE(name,nr,p) \

 (__builtin_constant_p(nr) ? \

  ____atomic_##name(nr, p) : \

  _##name##_le(nr,p))


锁实现的版本:

static inline void ____atomic_set_bit(unsigned int bit, volatile unsigned long *p)

{

 unsigned long flags;

 unsigned long mask = 1UL << (bit & 31);

 p += bit >> 5;

 raw_local_irq_save(flags);

 *p |= mask;

 raw_local_irq_restore(flags);

}

汇编版本:

ENTRY(_set_bit_le)
 bitop orr
ENDPROC(_set_bit_be)



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值