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

测试代码

@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并不奇怪

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,857评论 0 9
  • 没有抨击,也没有鼓吹。我们可以选择高晓松,也可以选择买房。但每一选择的,都应该是我们想要的,而不是跟风。 (一) ...
    阿来顾问阅读 201评论 0 1
  • 六岁那年 因为爸妈工作需要 我们全家搬到了海滨城市 也就是那一年 我成了小莫的邻居 其实小莫全名叫莫艾言 他父亲叫...
    小阿姨吖阅读 425评论 0 1
  • 这段时间明明感到很忙,却回忆不起自己多做了什么,只是忽然想到过去的某个瞬间,掰着手指算着过去了多少年或者多少月或者...
    二千一阅读 189评论 0 0