加载中…
个人资料
行者无疆-超越
行者无疆-超越
  • 博客等级:
  • 博客积分:0
  • 博客访问:23,328
  • 关注人气:1
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
相关博文
推荐博文
正文 字体大小:

Android原子操作的实现原理

(2014-02-13 18:03:16)
标签:

android

原子操作

it

分类: Android的同步和消息

Android原子操作的实现方式和CPU的架构有密切关系,现在的原子操作一般都是在CPU指令级别实现的,这样不但简单,而且效率非常高。下面看看arm平台下Android是如何实现原子操作的。

虽然原子操作的接口函数有十来个,但是实际上只有两个函数中通过汇编代码实现了原子操作:函数android_atomic_addandroid_atomic_cas,其他的函数都是在内部调用它们而已。这两个函数的原理差不多,下面我们以加法为例来了解一下原子变量的实现原理。函数android_atomic_add的代码如下:

extern ANDROID_ATOMIC_INLINE

int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr)

{

    int32_t prev, tmp, status;

    android_memory_barrier();

    do {

        __asm__ __volatile__ ("ldrex %0, [%4]\n"

                              "add %1, %0, %5\n"

                              "strex %2, %1, [%4]"

                              : "=&r" (prev), "=&r" (tmp),

                                "=&r" (status), "+m" (*ptr)

                              : "r" (ptr), "Ir" (increment)

                              : "cc");

    } while (__builtin_expect(status != 0, 0));

    return prev;

}  

上面代码中的宏ANDROID_ATOMIC_INLINE的定义是:

#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline))

实际上就是把函数规定为inline函数。

android_memory_barrier是告诉CPU这里需要内存屏障。下节会介绍内存屏障。

接下来是一段内嵌汇编,这段汇编可以用伪代码来表示:

do {

ldrex  prev[ptr]

add  tmp,  prev,  increment

strex  status,  tmp, [ptr]

} whiile(status != 0)

add指令的前后有两条看上去比较陌生的指令:ldrexstrex。这两条是AMRV6新引入的同步指令。ldrex指令的作用是把指针ptr指向的内容放到prev变量中,同时给执行处理器做一个标记(tag),标记上指针ptr的地址,表示这个内存地址已经有一个CPU正在访问。当执行到strex指令时,它会检查是否存在ptr的地址标记,如果标记存在,strex指令会把add指令执行的的结果写入指针ptr指向的地址,并且返回0,然后清除该标记。返回的结果0会放在status变量中,这样循环将结束。

如果在strex指令执行前发生了线程的上下文切换,在切换回来后,ldrx指令设置的标志将会被清除。这时再执行strex指令时,由于没有了这个标志,strex指令将不会完成对ptr指针的存储操作,而且status变量中的返回结果是1。这样循环不能结束,重新开始执行,直到成功为止。

__builtin_expectgcc的内建函数,有两个参数,第一个参数是一个表达式,第二个参数是一个值。表达式的计算结果也是函数的结果。__builtin_expect是用来告诉gcc预测表达式更可能的值是什么,这样gcc会根据预测值来优化代码。代码中表达的含义是预测“status!=0”这个表达式的值为“0”,也就是预测while循环将结束。

 

内嵌汇编可以参考本人的博文:gcc内嵌汇编介绍


 

0

阅读 评论 收藏 转载 喜欢 打印举报/Report
  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

    新浪BLOG意见反馈留言板 电话:4000520066 提示音后按1键(按当地市话标准计费) 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有