核心数据死锁

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

occ*_*lus 5

听起来这个问题出现在你的应用程序的线程/互斥/逻辑(或缺少)中,这些代码需要在同一时间内使用Core Data.

一个经常被忽视的线程规则:

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

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

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

一般事项:

NSManagedObjectContext锁定它NSPersistentStoreCoordinator何时使用它,所以只有一个PSC应该不是问题.

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

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

更新

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

你确定你是fetchEntity:从创建它的同一个线程调用你的方法NSManagedObjectContext吗?如何创建上下文,何时创建?

看到这个问题和答案:NSManagedObjectContext已锁定