美文网首页
多线程操作nonatomic属性引起的crash

多线程操作nonatomic属性引起的crash

作者: 宇哥说 | 来源:发表于2017-10-18 13:54 被阅读0次

    测试代码

    @interface ViewController ()
    @property (nonatomic, strong)NSObject *obj;
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        for (int i = 0; i < 10000000; i++) {
            NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(func) object:nil];
            [thread start];
        }
    }
    
    -(void)func
    {
        self.obj = [[NSObject alloc] init];
    }
    @end
    
    屏幕快照 2017-10-18 下午1.52.38.png

    atomic和nonatomic原理

    来看一下苹果开源的objc4源码,在 objc-accessors.mm文件中有很多的 getter 与 setter 方法的实现,这些实现都是为了 @property 做准备的,最终setter方法都会调到reallySetProperty()这个方法中,代码如下:

    static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic)
    {
        id oldValue;
        id *slot = (id*) ((char*)self + offset);
        if (!atomic) {
            oldValue = *slot;
            *slot = newValue;
        } else {
            spinlock_t& slotlock = PropertyLocks[slot];
            slotlock.lock();
            oldValue = *slot;
            *slot = newValue;       
            slotlock.unlock();
        }
        objc_release(oldValue);
    }
    

    atomic 与 nonatomic 的区别仅仅是对oldValue和slot赋值是否加锁。多线程中操作nonatomic属性时,如果某一线程在oldValue赋值后中断,那么另一线程执行oldValue赋值时,由于没有执行 *slot = newValue赋值和objc_release释放原值,所以oldValue赋值还是之前的,那么此时2个线程中oldValue指向的都是线程中断前的值,执行objc_release时释放2次,引起crash

    解决方法

    解决方法非常简单,nonatomic改成atomic即可
    展开来说,这个问题是多线程写临界区的问题,引起crash并不奇怪

    相关文章

      网友评论

          本文标题:多线程操作nonatomic属性引起的crash

          本文链接:https://www.haomeiwen.com/subject/juasuxtx.html