在Objective C中我使用了来自各种线程的NSMutableArray实例,并且我正在使用@synchronized来使其线程安全。目前我对这个数组的所有访问都受到@synchronized块的保护,甚至是objectAtIndex:方法。不过我想知道哪些方法确实需要用@synchronized保护。我需要保护读取权限吗?
如果'ObjectAtIndex'在'removeObject'的同时没有受到保护和调用,会发生什么?
如果所有方法都受@synchronized保护,性能如何? (我正在编写一个tcp / udp游戏服务器,如果它会降低性能或生成锁定,我真的不想过度保护这些数组)。
例如我假设'containsObject:'方法将枚举以查找对象,并且我应该避免在另一个线程中对'removeObject:'进行concurent调用。
也许一个好的解决方案是拥有太多不同的锁(用于读写访问)......
欢迎提供帮助和建议!
非常感谢。
请在下面找到示例代码来说明:
@interface TestClass : NSObject
{
NSMutableArray * array;
}
@end
@implementation TestClass
- (id)init
{
self = [super init];
if (self)
{
array = [NSMutableArray array];
}
return self;
}
-(id)objectAtIndex:(NSUInteger)index
{
@synchronized(array) **// IS IT USEFUL OR NOT ??**
{
return [array objectAtIndex:index];
}
}
-(void)removeObject:(id)object
{
@synchronized(array)
{
[array removeObject:object];
}
}
-(void)compute
{
@synchronized(array)
{
for (id object in array)
{
[object compute];
}
}
}
@end
答案 0 :(得分:5)
是的,您必须同步读取访问以防止它们与突变同时发生。但是,读访问可以安全地与其他读访问同时运行。
如果您有多个读者,那么值得研究读写锁定方案。您可以使用pthread读写锁(即pthread_rwlock_...()
)。
或者,您可以在OS X 10.7+和iOS 5+上使用GCD和“屏障”例程。创建专用并发队列。以正常方式向其提交所有读取操作(例如dispatch_sync()
)。使用诸如dispatch_barrier_async()
之类的屏障例程向其提交变异操作。 (它可以是异步的,因为您通常不需要知道突变在继续之前已经完成。您只需要知道在提交突变后提交的所有读取都将看到突变的结果,并且屏障保证了这一点。 )
如果您有权访问WWDC 2011 session video for Session 210 - Mastering Grand Central Dispatch,则可以了解详情。
答案 1 :(得分:0)
你需要意识到你正在做的事情实际上并没有太大帮助。例如,如果你的数组有10个元素,你调用[myObject objectAtIndex:9]而另一个线程调用[myObject removeObject:someObject],那么第一个调用可能会访问一个不再存在的数组元素并抛出异常。
如果其他线程可以删除或插入对象,则objectAtIndex不是很有用。