android atomic 线程同步,iOS底层 -- 多线程之atomic、读写安全

一、atomic

atomic用于保证属性setter、getter的原子性操作,相当于在getter和setter内部加了线程同步的锁

可以参考源码objc4的objc-accessors.mm

setter方法实现

static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)

{

if (offset == 0) {

object_setClass(self, newValue);

return;

}

id oldValue;

id *slot = (id*) ((char*)self + offset);

if (copy) {

newValue = [newValue copyWithZone:nil];

} else if (mutableCopy) {

newValue = [newValue mutableCopyWithZone:nil];

} else {

if (*slot == newValue) return;

newValue = objc_retain(newValue);

}

if (!atomic) {

oldValue = *slot;

*slot = newValue;

} else {

spinlock_t& slotlock = PropertyLocks[slot];

slotlock.lock();

oldValue = *slot;

*slot = newValue;

slotlock.unlock();

}

objc_release(oldValue);

}

get方法实现

id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {

if (offset == 0) {

return object_getClass(self);

}

// Retain release world

id *slot = (id*) ((char*)self + offset);

if (!atomic) return *slot;

// Atomic retain release world

spinlock_t& slotlock = PropertyLocks[slot];

slotlock.lock();

id value = objc_retain(*slot);

slotlock.unlock();

// for performance, we (safely) issue the autorelease OUTSIDE of the spinlock.

return objc_autoreleaseReturnValue(value);

}

分析

nonatomic和atomic

atom:原子,不可再分割的单位

atomic:原子性

给属性加上atomic修饰,可以保证属性的setter和getter都是原子性操作,也就是保证setter和gette内部是线程同步的

@property (copy, atomic) NSString *name;

- (void)setName:(NSString *)name {

// 加锁

_name = name;

// 解锁

}

- (NSString *)name {

// 加锁

return _name;

// 解锁

}

它并不能保证使用属性的过程是线程安全的

@property (strong, atomic) NSMutableArray *data;

Person *p = [[Person alloc] init];

p.data = [NSMutableArray array];

// 以下操作就不能保证线程安全了

for (int i = 0; i < 10; i++) {

dispatch_async(dispatch_get_global_queue(0, 0), ^{

[p.data addObject:@"1"];

});

}

虽然data属性是声明为atomic,但是也只是在p.data(实际上调用了get方法)和p.data = [NSMutableArray array];(实际上调用了set方法)是安全的。但是多条线程同时添加对象时,即[p.data addObject:@"1"];并不能保证线程安全。

二 读与写的方案

思考如何实现以下场景

同一时间,只能有1个线程进行写的操作

同一时间,允许有多个线程进行读的操作

同一时间,不允许既有写的操作,又有读的操作

上面的场景就是典型的“多读单写”,经常用于文件等数据的读写操作,iOS中的实现方案有

pthread_rwlock:读写锁

dispatch_barrier_async:异步栅栏调用

2.1 pthread_rwlock

等待锁的线程会进入休眠

2b35018f4c00

代码例子如下

#import

@property (assign, nonatomic) pthread_rwlock_t lock;

- (void)viewDidLoad {

[super viewDidLoad];

// 初始化锁

pthread_rwlock_init(&_lock, NULL);

dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

for (int i = 0; i < 10; i++) {

dispatch_async(queue, ^{

[self read];

});

dispatch_async(queue, ^{

[self write];

});

}

}

- (void)read {

pthread_rwlock_rdlock(&_lock);

sleep(1);

NSLog(@"%s", __func__);

pthread_rwlock_unlock(&_lock);

}

- (void)write {

pthread_rwlock_wrlock(&_lock);

sleep(1);

NSLog(@"%s", __func__);

pthread_rwlock_unlock(&_lock);

}

- (void)dealloc {

pthread_rwlock_destroy(&_lock);

}

执行结果

2b35018f4c00

2.2 dispatch_barrier_async

这个函数传入的并发队列必须是自己通过dispatch_queue_cretate创建的

如果传入的是一个串行或是一个全局的并发队列,那这个函数便等同于dispatch_async函数的效果

重要方法

// 初始化队列

dispatch_queue_t queue = dispatch_queue_create("rw_queue", DISPATCH_QUEUE_CONCURRENT);

// 读

dispatch_async(self.queue, ^{

[self read];

});

// 写

dispatch_barrier_async(self.queue, ^{

[self write];

});

原理如下

2b35018f4c00

代码例子如下

@property (strong, nonatomic) dispatch_queue_t queue;

// 栅栏

- (void)barrier_async_test {

self.queue = dispatch_queue_create("rw_queue", DISPATCH_QUEUE_CONCURRENT);

for (int i = 0; i < 5; i++) {

dispatch_async(self.queue, ^{

[self read];

});

dispatch_async(self.queue, ^{

[self read];

});

dispatch_barrier_async(self.queue, ^{

[self write];

});

}

}

- (void)read {

sleep(1);

NSLog(@"read");

}

- (void)write {

sleep(1);

NSLog(@"write");

}

执行结果如下

2b35018f4c00

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值