核心数据死锁

时间:2013-03-11 10:02:01

标签: ios objective-c cocoa core-data deadlock

我正在进行两次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

编辑:访问Core Data的不同部分正在尝试执行获取请求。他们都在调用这种方法:

NSArray *reminders = [[CoreDataHelper sharedInstance] fetchEntity:APReminderEntity predicate:nil andSortDescriptors:[NSArray arrayWithObject:dateAscendingDescriptor] inManagedObjectContext:nil];

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;
}

编辑2:我刚尝试将我的获取请求放在@synchronized块中(如此post中所示),到目前为止似乎效果很好..我正在通过正确的线程访问我的MOC .. MOC被初始化为_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];

2 个答案:

答案 0 :(得分:5)

听起来问题出现在你的应用程序的线程/互斥/逻辑(或缺少它)周围,希望在同一时间内使用Core Data的相关代码部分。

经常被忽视的线程规则:

  

在语言或API中使用线程构造并不一定意味着您的代码是线程安全的!

没有看到你的代码和逻辑,很难说更多。访问Core Data的不同部分有哪些?

作为一般策略,一种消除死锁的方法可能是将违规的核心数据访问代码收集到仅管理核心数据访问的控制器对象中。它可以负责避免代码丢失的任何死锁条件。

一般事项:

NSManagedObjectContext在使用它时锁定NSPersistentStoreCoordinator,因此只有一个PSC应该不是问题。

请确保遵循Core Data中的线程规则。特别是,每个NSManagedObjectContext只能从一个线程访问 - 即创建它的线程。

有关更多讨论,请参阅示例:

<强>更新

我很确定你的问题是你从错误的线程访问NSManagedObjectContext。您必须从创建它的同一线程访问上下文。请验证您是否在代码中正确执行了此操作。

您确定从创建fetchEntity:的同一线程中调用了NSManagedObjectContext方法吗?如何创建该上下文以及何时创建?

请参阅此问题和答案:NSManagedObjectContext Locked

答案 1 :(得分:0)

我有相同的结果但不同的问题。我已经多线程已经存在的coredata应用程序。它只使用主线程。

我根据主线程是否在主线程上指定要使用的上下文。使用dispatch_sync之类的东西(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND) 可能会把你放在主线程上(这是一个苹果优化)。这使我混合上下文对象并导致死锁