串行队列上的核心数据堆栈导致死锁

时间:2015-03-31 20:19:04

标签: ios multithreading core-data deadlock realm

我试图将核心数据数据库迁移到Realm(介于0到2百万行之间),并且遇到了我认为不应该发生的死锁。< / p>

从Singleton类开始,我就像这样启动迁移:

_queue = dispatch_queue_create("DiagnosticMigrationQueue", NULL);
    dispatch_async(_queue, ^{
        _realmMigrator = [[CoreDataToRealmMigrator alloc] init];
        [_realmMigrator performMigrationToRealm];
    });

performMigrationToRealm方法中,我设置了核心数据堆栈:

- (void) performMigrationToRealm
    {
    self.migrationIsRunning = YES;

    NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] lastObject];
    url = [url URLByAppendingPathComponent:@"persistentStore"];

    NSError *error;

    NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
    context.persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
    [context.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
                                                 configuration:@"DiagnosticData"
                                                           URL:url
                                                       options:nil
                                                         error:&error];

了解检查:创建队列时,尚未设置任何Core Data堆栈。因此,NSManagedObjectContext仅在GCD决定放置块的任何线程上创建。

到目前为止,这么好。没问题。我现在运行一个方法 - 以100,000个批量 - 抓取实体中的所有NSManagedObjectIds。它看起来像这样:

for (NSInteger numberOfMigratedBatches = 0; numberOfMigratedBatches < totalNumberOfBatches; numberOfMigratedBatches++)
{
    NSArray *samples = [context executeFetchRequest:fetchRequest error:&error];
    if (samples && !error) 
    {
        [self transferWeightSamplesToRealmWithObjectIds:samples withContext:context];
    }
    [context reset];
    fetchRequest.fetchOffset = batchSize * (numberOfMigratedBatches+1);
}

时髦的一行是上面代码块中的fetchRequest。即使我已经在串行队列上启动了这个过程,我还是以某种方式结束了这个:

Three threads stuck on the same line of code

每个minion_duties2线程都停留在同一行代码上,即上面的fetchRequest

这里发生了什么?我理解队列!=线程,并且GDC会将我的代码放在适合的任何线程上。但是,我不希望它会将我的代码放在三个线程上。另外,什么是com.apple.root.user-initiated-qos.overcommit?我会说它过度使用了。我只希望这段代码运行一次!

1 个答案:

答案 0 :(得分:0)

因此,从技术上讲,这不是您发布的问题的答案,但是,它可能会为您提供一种方法,可以避免您遇到的问题(解决方法?)。

由于我的猜测是尝试在导致死锁的几个不同线程上执行的几个不同的获取请求,我建议不要手动执行批处理,而是通过设置来完成NSFetchRequest上的fetchBatchSize属性,让核心数据为你做,因此避免完全执行多次获取请求,如果内存使用是个问题,请尝试将for循环的内部包装在autoreleasepool块中(我猜测transferWeightSamplesToRealmWithObjectIds:withContext:方法中有一个for循环。

核心数据有一个名为batching&amp; amp;断裂。来自Apple documentation of NSFetchRequest

  

如果设置非零批量大小,则返回对象集合   当执行获取被分成批次时。当获取时   执行,评估整个请求和所有的身份   匹配记录的对象,但不超过batchSize对象的数据   将一次从持久存储中获取。阵列   从执行请求返回的将是一个代理对象   透明地按需批量故障。 (在数据库方面,这是一个   内存中的光标。)

希望这对你有所帮助。