2015-05-29 30 views
4

我有一个“sharedStore” - 模式的单身人士的NSMutableArray。NSMutableArray线程并发与GCD

公开地说,它只能通过将其转换为NSArray的方法访问。在类,它是

@property (nonatomic, copy) NSMutableArray *myItems; 

这个数组永远不会被操纵outsdie单身,但ViewControllers发送单消息来操作该控制器。其中一些消息清空阵列,一些重新填充它,等等。

已经结束了在一个方法调用中数组为空而下一个方法尚未空的情况下,我开始实现一些并发行为。

下面是我在做什么至今:

在单身的.m文件,我有一个

@property (nonatomic, strong) dispatch_queue_t arrayAccessQueue; 

在我单身的初始化它被创建为一个串行队列。然后,每一个有什么关系改变此数组从dispatch_sync电话中这样做,例如方法:

dispatch_sync(self.arrayAccessQueue, ^{ 
    [_myItems removeAllObjects]; 
}); 

这更好的事情做,并取得了我的应用程序表现得更加顺畅。然而,除了修正上述一个奇怪的行为之外,我无法量化它。我也觉得我在黑暗中可能潜伏在表面之下的任何问题。

这种模式对我有意义,但我应该使用别的东西,如@synchronizeNSLockNSOperationQueue?这会回来咬我吗?

+0

顺便说一句 - 你是否正确地为你的'myItems'属性实现了一个明确的setter方法?如果不是,由于mutable属性上的'copy'属性,你将会遇到问题。 – rmaddy

+0

嗯。我不知道。你的意思是'_myItems = [myItems copy]'?我认为编译器现在自动执行了这个操作,而且它不需要再明确地完成了?我错了吗? – magiclantern

+1

问题在于[myItems copy]返回一个'NSArray',而不是'NSMutableArray',即使在可变数组上调用时也是如此。你需要重写'setMyItems:'方法并调用mutableCopy'。 – rmaddy

回答

3

使用dispatch_sync就可以了,只要您包装所有阵列的读写操作并确保它是串行队列即可。

但是,你可以通过允许并发读取来改进。为此,请在所有阵列读取周围使用dispatch_sync,并在所有阵列写入周围使用dispatch_barrier_sync。并设置队列为并发。

这样做是否确保一次只能进行一次写操作,读操作将被阻塞直到写操作完成,并且写操作将一直等到所有当前读操作完成。

+0

谢谢。我也会使用屏障去除物体,对吗? – magiclantern

+0

是的,因为删除被认为是“写入”。任何改变阵列内容的东西都是“写入”,需要使用屏障同步。 – rmaddy

+2

从技术上讲,对于只读操作,“NSMutableArray”也不是线程安全的。除非文档另有明确说明,否则您不能假设线程安全。 (不过,我确定它实际上在读取操作期间实现为线程安全)。这可能需要在文档中进行说明。 – bbum

0

使用GCD是正确的选择。唯一的“难题”是你需要对该队列执行所有操作:添加,删除,插入等。

我还会提到你需要确保你不使用并发队列。你应该使用一个串行队列,无论如何这是默认的。

1

使用GCD并发队列并为阵列提供排序访问器,您可以在读写时使用dispatch_sync同时读取和dispatch_barrier_async同步读写。

- (id)methodToRead { 
    id __block obj = nil; 
    dispatch_sync(syncQueue, ^{ 
    obj = <#read_Something#>; 
    }); 
    return obj; 
} 

- (void) methodsForWriting:(id)obj { 
    dispatch_barrier_async(syncQueue, ^{ 
    // write passing obj to something 
    }); 
} 

这将保证期间写的一切是从读锁定。

+0

不应该是'dispatch_barrier_sync'写作吗? –

+0

取决于,_async表示方法在块执行之前返回。但块执行顺序应由同步队列本身保证。当然这听起来更合适。 – Andrea