Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3786094
  • 博文数量: 880
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 6155
  • 用 户 组: 普通用户
  • 注册时间: 2016-11-11 09:12
个人简介

To be a better coder

文章分类

全部博文(880)

文章存档

2022年(5)

2021年(60)

2020年(175)

2019年(207)

2018年(210)

2017年(142)

2016年(81)

分类: LINUX

2016-12-05 10:50:36

原文地址:Linux元素集合—原子变量 作者:fsfilove

所谓原子操作,就是该操作绝不会在执行完毕前被任何其他任务或事件打断。这种情况一般出现在一个变量会被多个线程使用。那么在其使用时需要避免中断。
具体下面原子操作的概念可以参考《linux内核设计与实现》第八章 内核同步方法。
在Linux里面提供了原子操作

typedef struct {
volatile int counter;
} atomic_t;


原子整数操作

描述

ATOMIC_INIT(int i)

  在声明一个atomic_t变量时,将它初始化为i

int atomic_read(atomic_t *v)

  原子地读取整数变量v

void atomic_set(atomic_t *v, int i)

  原子地设置v值为i

void atomic_add(int i, atomic_t *v)

  原子地给vi

void atomic_sub(int i, atomic_t *v)

  原子地从vi

void atomic_inc(atomic_t *v)

  原子地给v1

void atomic_dec(atomic_t *v)

  原子地给v1

int atomic_sub_and_test(int i, atomic_t *v)

  原子地从vi,若结果等于0返回真,否则返回假

int atomic_add_negative(int i, atomic_t *v)

  原子地从vi,若结果是负数返回真,否则返回假

int atomic_dec_and_test(atomic_t *v)

原子地从v1,若结果等于0返回真,否则返回假

int atomic_inc_and_test(atomic_t *v)

  原子地从v1,若结果等于0返回真,否则返回假

上边就是具体的函数,这些函数在不同体系里面是不同的实现。接下来分析arm的代码。

能分析一个函数,其他的函数也就简单了,所以就先分析atomic_set

static inline void atomic_set(atomic_t *v, int i)
{
unsigned long tmp;


__asm__ __volatile__("@ atomic_set\n" /*__volatile__这个是告诉编译器别优化下面的代码*/
"1: ldrex %0, [%1]\n"  /*将v->counter的值存入到tmp中*/
" strex %0, %2, [%1]\n"  /*这条指令是如果是exclusive access,这将i值存储到v->counter , 如果不是,什么也不做*/
" teq %0, #0\n" /*判断tmp的值是不是0*/
" bne 1b"  /*如果不是,这跳转到1,如果是则基本完成了atomic_set的命令*/
: "=&r" (tmp) /*%0*/
: "r" (&v->counter), "r" (i)   /*%1 , %2*/
: "cc");
}

原子变量其他的函数基本相同。

而对于有些函数会有如下情况

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


smp_mb();  /*这里只是多了smp_mb() , 但在对于单cpu,这里对于并没有多少工作。*/


__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");


smp_mb();


return result;
}

对于原子变量在代码使用问题是比较简单的。

atomic_t v; /* define v */
atomic_t v = ATOMIC_INIT(0); /* define u and initialize it to zero */
Operations are all simple:
atomic_set(&v, 4); /* v = 4 (atomically) */
atomic_add(2, &v); /* v = v + 2 = 6 (atomically) */
atomic_inc(&v); /* v = v + 1 = 7 (atomically) */















阅读(816) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~