免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 15741 | 回复: 15
打印 上一主题 下一主题

atomic_read 请教 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-04-02 11:16 |只看该作者 |倒序浏览
请教大家一个问题,

typedef struct { volatile int counter; } atomic_t;

#define ATOMIC_INIT(i)        { (i) }

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

原子读操作定义如上,但是我觉得没有做什么操作,只是返回v的counter字段值,具体是怎样保证atomic_read是原子读的呢?

关键字 volatile 也不能起到不被中断的作用吧。

论坛徽章:
0
2 [报告]
发表于 2010-04-02 12:34 |只看该作者
可以看到,atomic系列对于不同的体系结构有着不同的定义。
在很多体系结构下,对于一个字的访问本身就是原子的,不存在读了半个字(或不足一个字的若干字节)又被中断的情况。所以就直接这么实现了。
有些特殊的体系结构可能就需要通过其他手段来保证这一点,你会看到atomic系列有着特别的实现。

论坛徽章:
0
3 [报告]
发表于 2010-04-02 13:59 |只看该作者
可以看到,atomic系列对于不同的体系结构有着不同的定义。
在很多体系结构下,对于一个字的访问本身就是原 ...
kouu 发表于 2010-04-02 12:34



    我在i386平台下,请解释的具体些好吗?
    因为我觉得读可以是原子操作,但是写操作要做三个动作:
1. CPU从内存读操作数
2. 修改操作数
3. 写回到内存
这个操作我觉得不是原子操作吧

在完成1步骤后,执行会不会被打断呢?

请教了

论坛徽章:
0
4 [报告]
发表于 2010-04-02 14:34 |只看该作者
本帖最后由 kouu 于 2010-04-02 14:43 编辑

LS所说的“操作数”是什么?

  操作数(operand)
  计算机指令中的一个组成部分。
  它规定了指令中进行数字运算的量。
  通常一条指令均包含操作符和操作数。

也就是说,对于内存读写的指令,要读写的内存地址就是操作数。

为什么要修改操作数呢?


我猜想LS指的应该是 read -> modify -> write 的过程? 如果是的话,那么 atomic_set 只管 write 这一步,只保证这一步是原子的。而不保证三个步骤的原子性。

如果想要保证三个步骤的原子性,只能通过其他手段,比如锁总线。
例如,atomic系列的atomic_inc,它可以使“读内存、加1、写内存”三步是原子的。它就是通过锁总线来实现的。

论坛徽章:
0
5 [报告]
发表于 2010-04-02 15:13 |只看该作者
LS所说的“操作数”是什么?

  操作数(operand)
  计算机指令中的一个组成部分。
  它规定了指 ...
kouu 发表于 2010-04-02 14:34



        谢谢,明白些了,难怪
static __inline__ void atomic_add(int i, atomic_t *v)
{
        __asm__ __volatile__(
                LOCK "addl %1,%0"
                :"=m" (v->counter)
                :"ir" (i), "m" (v->counter));
}
使用了lock命令,
还有一点请教,就是在单处理器情况下,lock宏定义为空,那么上面的atomic_add函数
实际上也没有锁定总线,那么怎么确保原子操作呢,因为这个还要涉及到更新操作?

论坛徽章:
0
6 [报告]
发表于 2010-04-02 16:40 |只看该作者
本帖最后由 kouu 于 2010-04-02 17:01 编辑

回复 5# tianhailong


CPU指令原子的,不可能出现指令执行到一半就被中断的情况。中断只能发生在指令与指令之间。

所以,在单处理器情况下,一条指令能完成的事情就是原子的。不管这条指令究竟做了多少事情。

多处理器情况下就不一样,一条CPU指令如果包含多个内存操作,则这多次操作之间可能有其他CPU也在操作内存,并且有可能它们操作的就是同一块内存。所以,在多处理器情况下,只进行一次内存读写的指令才是原子的。
如果想让进行多次内存读写的指令变成原子的,则需要锁总线。

论坛徽章:
0
7 [报告]
发表于 2010-04-02 17:23 |只看该作者
本帖最后由 tianhailong 于 2010-04-02 17:28 编辑
回复  tianhailong


CPU指令原子的,不可能出现指令执行到一半就被中断的情况。中断只能发生在指令与指 ...
kouu 发表于 2010-04-02 16:40



    谢谢,再请教一下,是否可以这样理解:一条汇编指令对应一条CPU指令,就是说每一条汇编指令的执行是原子操作,不可分割的?

    还有,read -> modify -> write 过程中 不保证三个步骤的原子性,为了保证原子性,使用了锁总线
    但是在单CPU环境下,LOCK定义为空,那么应该也没有锁总线,怎么保证这三个步骤的原子性呢?

论坛徽章:
0
8 [报告]
发表于 2010-04-02 17:41 |只看该作者
汇编里面有指令和伪指令之分,有些汇编指令并不是真正的CPU指令,比如写个宏什么的。但是多数情况下,还是跟CPU指令一一对应的。

如果read -> modify -> write不在一条指令中,需要多条指令来解决的话。就需要使用某种同步机制了。
比如通过暂时禁用中断,使本CPU上的执行流程不被打断;上锁,使其他CPU不能进入临界区。

论坛徽章:
0
9 [报告]
发表于 2010-04-02 17:45 |只看该作者
不好意思,再请教一下

    例如:
    int main() {
             i++;
             return 0;
    }
    其中i++对应汇编:
       8d 45 fc              lea    0xfffffffc(%ebp),%eax
       ff 00                   incl   (%eax)
是两条语句,就是说i++不是原子操作,而如果我们使用内联汇编,把i++写成
static __inline__ void atomic_inc(atomic_t *v)
{
        __asm__ __volatile__(
                 "incl %0"
                :"=m" (v->counter)
                :"m" (v->counter));
}

就可以保证,在一条指令完成,是原子操作,对吗?

论坛徽章:
0
10 [报告]
发表于 2010-04-02 18:03 |只看该作者
i++ 对应的就是 incl   (%eax) 这一条指令,lea    0xfffffffc(%ebp),%eax 只是在计算 i 的内存地址,并没有对 i 所对应的内存做操作。

atomic_inc 编译出来应该也是类似的造型
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP