Pet*_*rbo 1 cocoa deadlock core-data objective-c ios
我正在做2个Core Data提取,当它们大约在同一时间执行时,它们将导致主线程中的死锁,导致我的应用程序冻结.
提取是在主线程上进行的.处理它的一种方法是确保提取不是在同一时间进行的,但我无法控制何时进行提取.有没有其他办法可以避免这种僵局?
暂停应用程序时的堆栈跟踪是:
#0 0x9a5d191a in __psynch_mutexwait ()
#1 0x9166713b in pthread_mutex_lock ()
#2 0x01e5d591 in -[_PFLock lock] ()
#3 0x01e5d56a in -[NSPersistentStoreCoordinator lock] ()
#4 0x01e720ee in -[NSPersistentStoreCoordinator executeRequest:withContext:error:] ()
#5 0x01e70539 in -[NSManagedObjectContext executeFetchRequest:error:] ()
#6 0x0007cd62 in -[CoreDataHelper fetchEntity:predicate:andSortDescriptors:inManagedObjectContext:] at /xxx/CoreDataHelper.m:150
#7 0x000075f6 in -[RemindersListViewController refreshReminders] at /xxx/RemindersListViewController.m:64
#8 0x000082f8 in -[RemindersListViewController refreshGUI] at /xxx/RemindersListViewController.m:187
#9 0x00003735 in __58-[AppDelegate setTabCountAndScheduleRemindersInBackground]_block_invoke_2 at /xxx/AppDelegate.m:114
#10 0x022dc53f in _dispatch_call_block_and_release ()
#11 0x022ee014 in _dispatch_client_callout ()
#12 0x022de7d5 in _dispatch_main_queue_callback_4CF ()
#13 0x0261aaf5 in __CFRunLoopRun ()
#14 0x02619f44 in CFRunLoopRunSpecific ()
#15 0x02619e1b in CFRunLoopRunInMode ()
#16 0x02fd77e3 in GSEventRunModal ()
#17 0x02fd7668 in GSEventRun ()
#18 0x00d9dffc in UIApplicationMain ()
#19 0x0000297d in main at /xxx/main.m:16
Run Code Online (Sandbox Code Playgroud)
编辑:访问Core Data的不同部分正在尝试执行获取请求.他们都在调用这种方法:
NSArray *reminders = [[CoreDataHelper sharedInstance] fetchEntity:APReminderEntity predicate:nil andSortDescriptors:[NSArray arrayWithObject:dateAscendingDescriptor] inManagedObjectContext:nil];
Run Code Online (Sandbox Code Playgroud)
CoreDataHelper.m
- (NSArray *)fetchEntity:(NSString *)entity predicate:(NSPredicate *)predicate andSortDescriptors:(NSArray *)sortDescriptors inManagedObjectContext:(NSManagedObjectContext *)context {
DLogName()
if (context == nil) {
// Use default MOC
context = self.managedObjectContext;
}
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:entity inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDescription];
if (predicate != nil) {
[request setPredicate:predicate];
}
if (sortDescriptors != nil) {
[request setSortDescriptors:sortDescriptors];
}
NSError *error = nil;
NSArray *entities = [context executeFetchRequest:request error:&error];
if (entities == nil) {
DLog(@"There was an error fetching entity: %@ Error: %@", entity, [error userInfo]);
entities = [NSArray array];
}
return entities;
}
Run Code Online (Sandbox Code Playgroud)
编辑2:我只是试图把我取一个内部的请求@synchronized块(如本建议后),到目前为止,它似乎执行的很好...我访问我在正确的线程MOC ..商务部初始化为_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
听起来这个问题出现在你的应用程序的线程/互斥/逻辑(或缺少)中,这些代码需要在同一时间内使用Core Data.
一个经常被忽视的线程规则:
在语言或API中使用线程构造并不一定意味着您的代码是线程安全的!
没有看到你的代码和逻辑,很难说更多.访问Core Data的不同部分有哪些?
作为一般策略,消除死锁的方法可能是将违规的Core Data访问代码收集到仅管理核心数据访问的控制器对象中.它可以负责避免代码丢失的任何死锁条件.
一般事项:
NSManagedObjectContext锁定它NSPersistentStoreCoordinator何时使用它,所以只有一个PSC应该不是问题.
请务必遵循Core Data中的线程规则.特别是,每个NSManagedObjectContext线程只能从一个线程访问 - 即创建它的线程.
有关更多讨论,请参阅示例:
更新
我很确定你的问题是你NSManagedObjectContext从错误的线程访问.您必须从创建它的同一线程访问上下文.请验证您是否在代码中正确执行了此操作.
你确定你是fetchEntity:从创建它的同一个线程调用你的方法NSManagedObjectContext吗?如何创建上下文,何时创建?
看到这个问题和答案:NSManagedObjectContext已锁定