Ios NSMutableDictionary-EXC访问错误-同时读/写
我希望我的应用程序能得到一些帮助 我有一个设置,其中多个线程访问由singleton类拥有的共享Ios NSMutableDictionary-EXC访问错误-同时读/写,ios,objective-c,multithreading,nsmutablearray,core-foundation,Ios,Objective C,Multithreading,Nsmutablearray,Core Foundation,我希望我的应用程序能得到一些帮助 我有一个设置,其中多个线程访问由singleton类拥有的共享NSMutableDictionary。线程访问字典以响应下载JSON并对其进行处理。singleton类基本上防止了一些具有唯一id号的下载对象的复制 即 一次可以有多达5-10个线程同时调用processJSON 不是马上,而是在运行几分钟后(在iPhone上比在模拟器上更快),我得到了可怕的EXC坏访问 我承认不知道NSMutableDictionary是如何工作的,但我猜后台有某种哈希表,在分
NSMutableDictionary
。线程访问字典以响应下载JSON并对其进行处理。singleton类基本上防止了一些具有唯一id号的下载对象的复制
即
一次可以有多达5-10个线程同时调用processJSON
不是马上,而是在运行几分钟后(在iPhone上比在模拟器上更快),我得到了可怕的EXC坏访问
我承认不知道NSMutableDictionary
是如何工作的,但我猜后台有某种哈希表,在分配对象时需要更新,在访问对象时需要读取。因此,如果线程要对字典进行瞬时读/写操作,则可能会发生此错误-可能是因为对象在内存中移动了
我希望在这方面有更多知识的人能启发我
至于解决方案,我认为singleton类有一个最大并发操作数为1的
NSOperationQueue
,然后在我想访问NSDictionary
时使用operationWithBlock:
。唯一的问题是,它使调用processJSON
成为一个异步函数,我不能立即返回创建的对象;我得用一个街区,那样会有点混乱。有没有办法使用@synchronize
?这样做行得通吗?最简单的解决方案是在@synchronized块中删除访问dict的所有代码
串行操作队列很棒,但对我来说,这听起来有点过分了,因为你没有保护整个数据生态系统,只有一个结构。我想提请你注意Hot Clicks向你指出的线程编程指南的iOS版本部分。其中一种锁定机制,或者使用专用串行队列,可以帮助您实现线程安全 您对串行操作队列的直觉是有希望的,尽管人们经常会为此使用串行调度队列(例如,您可以从任何队列调用
dispatch\u sync
),实现与它交互的受控机制以及同步操作。或者,更好的是,您可以使用自定义并发队列(而不是全局队列),通过dispatch\u sync
执行读取,通过dispatch\u barrier\u async
执行写入,从而实现高效的读写器方案(如或中所述)
《并发编程指南》的这一节概述了与传统锁定技术相比,使用串行队列进行同步的一些基本原理
《并发编程指南》中的和应提供相当多的信息。“可变对象通常不是线程安全的。要在线程化应用程序中使用可变对象,应用程序必须使用锁同步对它们的访问。(有关更多信息,请参阅“原子操作”)。通常,集合类(例如,NSMutableArray、NSMutableDictionary)在涉及突变时不是线程安全的。也就是说,如果一个或多个线程正在更改同一个数组,则可能会发生问题。您必须锁定发生读写操作的位置,以确保线程安全。”(这来自文档的,但应适用于iOS。)特别是,我要提请您注意Hot Clicks向您指出的文档部分。其中的一种锁定机制,或使用专用串行队列,可以帮助您实现线程安全。顺便说一下,我认为您对串行操作队列的直觉是有希望的,尽管人们通常会使用串行调度队列为此(因此您可以从任何队列调用
dispatch\u sync
,将其发送到词典的串行队列),实现与之交互的受控机制以及同步操作。或者,如果使用操作队列,当后台操作队列希望将您的操作提交到串行队列时,您可以使用waitUntilFinished
。非常感谢您的回复。我看了文章并我认为解决方案在于GCD。我真的应该进一步探索API!dispatch\u sync可用于读取,dispatch\u barrier\u async可用于写入。这样,我可以处理检查对象是否同步存在的部分,并在不久之后将新对象写入字典时将其交还给调用方。dispatch队列几乎没有更多的代码,而且速度也快了一点,这取决于场景……但总体上我同意……为了保护一个数据结构,只@syncronized(theDict)似乎不那么混乱…答案中记录了这一点:我最终使用了GCD。看来,在多线程应用程序中使用并发队列,并使用dispatch_sync进行读取,dispatch_barrier_async进行写入,是一种在NSMutableDictionary中工作的好方法。@Vazzyb同意(只要并发队列不是全局队列,而是您使用DISPATCH\u queue\u concurrent
创建的队列)。显然,您不希望在全局队列上设置障碍。(我知道您知道这一点,但我只为将来的读者添加此警告。)
//NSURLConnection calls:
[[Singleton sharedInstance] processJSON:data];
@interface Singleton
+ (Singleton) sharedInstance;
@property (nonatomic, strong) NSMutableDictionary *store;
@end
@implementation
-(void) processJSON:(NSData*)data {
...
someCustomClass *potentialEntry = [someCustomClass parse:data];
...
if(![self entryExists:potentialEntry.stringId])
[self addNewEntry:potentialEntry];
...
}
-(void) entryExists:(NSString*)objectId {
if(self.store[objectId])
return true;
else return false;
}
-(void) addEntry:(someCustomClass *object) {
self.store[object.stringId] = object;
}