Objective c NSLock&x2B;原子性质与非原子性质
我对objective C相当陌生。如果我有一个类属性,在API调用等异步事件期间可能会被修改,那么什么是确保在其他线程访问该属性时更改该属性不会导致崩溃的最佳方法 据我所知,我有两个选择: 1)NSLock+原子属性 …但在这种情况下,我似乎必须为每次读写锁定属性,对我来说,这将破坏将其设置为原子的目的 2)非原子性质 我也可以将它设置为非原子,但是我想我必须在主线程上进行所有的读/写操作。作为API调用的结果,有没有一种方法可以做到这一点?成功的API响应后对委托的回调是在为该API调用打开的线程上,还是在主线程上?如果它在不同的线程上,我可以把它放回主线程吗?具体地说,我担心一个NSArray在另一个线程循环时被更改Objective c NSLock&x2B;原子性质与非原子性质,objective-c,multithreading,thread-safety,locking,foundation,Objective C,Multithreading,Thread Safety,Locking,Foundation,我对objective C相当陌生。如果我有一个类属性,在API调用等异步事件期间可能会被修改,那么什么是确保在其他线程访问该属性时更改该属性不会导致崩溃的最佳方法 据我所知,我有两个选择: 1)NSLock+原子属性 …但在这种情况下,我似乎必须为每次读写锁定属性,对我来说,这将破坏将其设置为原子的目的 2)非原子性质 我也可以将它设置为非原子,但是我想我必须在主线程上进行所有的读/写操作。作为API调用的结果,有没有一种方法可以做到这一点?成功的API响应后对委托的回调是在为该API调用打开
最好的方法是什么?它更像是3个选项:
apipthread\u mutex*
apiNSLock
@synchronized
- 信号量
- 调度API
NSArray
。如果这是一个copy
属性(应该是),那么atomic在极少数情况下可以让您在实践中通过不可变拷贝安全地获取/设置数组。然而,在实践中,拥有一个只不过是指向不可变数组实例的指针的类并不是很有用;通常,您希望对该数组执行某些操作,并且通常希望以线程安全的方式与对象交互。有问题的锁的含义也可用于对数组元素的互斥(如果操作正确)
那么,为了保证NSMutableArray
ivar的互斥性,您需要在哪里进行锁定?设置时、获取时以及几乎每次发送消息时。即使询问其-count
或其元素,也应该包含一个锁,以消除任何竞争条件。当然,为了确保正确性,您可以将其封装在更高级别的操作中,并执行这些操作——一次获取锁
2) 非原子性质
原子的救不了你,非原子的也救不了你。在这种情况下,Atomic只会使您免于某些潜在的竞争条件。因此,您通常应该使用非原子,因为您已经需要引入完全互斥来保证没有竞争条件
成功的API响应后对委托的回调是在为该API调用打开的线程上,还是在主线程上
这取决于API
如果它在不同的线程上,我可以把它放回主线程吗
是的,您可以将其添加到主线程的运行循环或使用调度队列。除非工作需要在一个特定的线程上进行,否则这是“胡扯”——最明显的情况是在更新AppKit或UIKit视图时。我想用justin的选项“dispatch API”作为一个简短的例子: 通过在专用串行队列上执行所有访问,可以确保对共享资源的并发访问安全,我们称之为“同步队列” 这个“sync_队列”可能是一个类的私有队列,该类的ivar是您要修改的资源 现在可以定义读/写非原子属性,例如:
@propery(非原子)NSArray*数组代码>
写访问可以实现如下所示:
- (void) setArray:(NSArray* newValue)
{
dispatch_async(sync_queue, ^{
_array = newValue;
});
}
请注意,写访问是异步的
对该属性的读取访问将按如下方式实现:
- (NSArray*) array:(NSArray* value)
{
if (dispatch_get_specific(SyncQueueID) == sync_queue_id)) {
return _array;
}
else {
__block NSArray* result = nil;
dispatch_sync(_sync_queue, ^{
result = _array;
});
return result;
}
}
与写访问不同,读访问需要同步。该方法还必须检查当前执行上下文是否已经是sync_队列或sync队列的子级或任何子级-否则,读取访问将导致死锁
为了识别当前执行上下文,我们在创建同步队列时使用函数将特定标识符与同步队列相关联。稍后,我们使用从当前队列、父队列或任何父队列获取该标识符。如果返回此特定标识符,则该方法将分别在同步队列上的