nonatomic,atomic和volatile 关键字

本博客对下面四中情况,进行真机测试:

    ●类中变量 int cant

    ●类中 volatile 变量int cnt

    ●类中 nonatomic 属性int cnt

    ●类中 atomic 属性int cnt

    关于volatile关键字可以参考:C语言中的Volatile关键字。意思是:volatile告诉编译器,计算变量i时,每次强制使用内存中的值,不要使用寄存器中的值。

    atomic,操作原子性 ,atomic 还是属性声明关键字中默认值。注意:它没有一个内存“加锁”的概念,而是一个寄存器“加锁(这里其实就是一个防死锁,不让别人继续访问正在修改的value)”的概念,保证每次都是寄存器中计算好的数据,而不是返回到内存中已经不用计算的数据。

    nonatomic:直接从内存中取数值,并没有一个加锁的保护来用于cpu中的寄存器计算Value,它只是单纯的从内存地址中,当前的内存存储的数据结果来进行使用。所以在多线程中,我们应该对这样的变量进行nonatomic声明,因为它一直都能响应getter方法,防止你数据取到一半,结果数据释放了,或者数据 还在其他线程中正在写入。这就避免了 取到的数据不是你预期的那一个(尽管这一个并不是 另外一个线程正在修改的数据)。

    经过测试数据如下:

demo 中的核心函数是:对 cnt变量++运算。执行1000000次(可以自己设置循环次数)

点击下载


从上图中得知:越往下平均时间消耗越长。normal 最短,atomic 最长。normal < volatile < nonatomic < atomic 

        ●正常情况下变量cnt的值是缓存到寄存器中的,但是volatile强制每次从内存中取值运算,内存比寄存器慢,结果就是volatile比normal慢。

        ●nonatomic比atomic要快的原因是:它直接访问内存的地址;不关心“其他线程是否改变这个数值”,并且中间没有死锁保护,它只需直接从内存中访问到当前内存地址中的能用到的数据即可(可以理解为getter方法一直都能返回数值,尽管折个数值在cpu中可能正在修改中)。

    

    atomic是线程不安全的。有些同学误认为多线程下加atomic关键字是安全,是不对的。

    经过atomic 修饰的变量cnt,仅仅只是在getter和setter的时候是原子操作,如果对cnt进行++运算,则不在atomic管理范围。

    比如下面的代码:

    @property int cnt;
    @synthesize cnt = _cnt;
    self.cnt = 0;
    for(i = 0 ; i < n ; i++)
    {
        self.cnt ++;
    }

汇编后,请看下面的汇编代码:

L:    movl cnt(%rip) ,%eax //将cnt的值移动到存储器 (load)

U:    incl %eax //++操作 (updte)

S:    movl %ecx,cnt(%rip)  //保存cnt的值到内存 (save)

    如果两个线程都在运行这个代码,cnt是共享变量(不同线程运行的栈是不同的)。那么,这三行汇编代码是临界区,即不能够中断,否则就会造成数据错误。

    Case1:L1->U1->S1->L2->U2->S2 翻译成文字就是:线程1加载cnt=0到寄存器,然后寄存器++ 将寄存器的值1保存到cnt。线程2在走一遍这个过程,最后cnt=2。这个顺序是没问题的。能够保证cnt的值能够++两次。

    Case2:L1->U1->L2->S1->U2->S2 翻译成文字就是:线程1加载cnt=0到寄存器,然后线程1的寄存器++操作。线程2加载cnt=0到寄存器,线程1将寄存器值1保存到cnt,线程2中寄存器++,线程2将寄存器的值(仍是1)保存到cnt。结果是错误的1.

我个人觉得关键字atomic的管辖范围没有覆盖到L,U,S这三条汇编操作的,所以atomic是线程不安全的。同样nonatomic也是线程不安全的。想要线程安全只有加锁。


***中间引用网友的博客 http://blog.csdn.net/a21064346/article/details/8086701 特此说明***

***牛X的文章 http://archive.atomicmpc.com.au/forums.asp?s=2&c=10&t=4594***

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值