Ios NSMutableDictionary-EXC访问错误-同时读/写

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是如何工作的,但我猜后台有某种哈希表,在分

我希望我的应用程序能得到一些帮助

我有一个设置,其中多个线程访问由singleton类拥有的共享
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;
  }