1

私は2つのコアデータフェッチを実行しています。これらがほぼ同時に実行されると、メインスレッドでデッドロックが発生し、アプリがフリーズします。

フェッチはメインスレッドで行われます。これに対処する1つの方法は、フェッチがほぼ同時に行われないようにすることですが、フェッチがいつ行われるかを制御することはできません。このデッドロックを回避する他の方法はありますか?

アプリを一時停止するときのスタックトレースは次のとおりです。

#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

編集:コアデータにアクセスするさまざまな部分がフェッチ要求を実行しようとしています。彼らは両方ともこのメソッドを呼び出しています:

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ブロック内に配置しようとしましたが(この投稿で提案されているように)、これまでのところうまくいくようです...正しいスレッドでMOCにアクセスしています..MOCは次のように初期化されます_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];

4

2 に答える 2

5

問題は、アプリケーションのスレッド化/ミューテックス/ロジック (またはそれらの欠如) にあり、ほぼ同時に Core Data を使用したいコードの依存部分にあるようです。

無視されがちなスレッドのルール:

言語または API でスレッド構造を使用しても、コードがスレッドセーフであるとは限りません。

コードとロジックを見ないと、それ以上のことは言えません。Core Data にアクセスするさまざまな部分は何をしようとしていますか?

一般的な戦略として、デッドロックを解消するためのアプローチは、コア データ アクセスのみを管理するコントローラー オブジェクトに問題のコア データ アクセス コードを収集することです。コードがスローしているデッドロック状態を回避する責任がある可能性があります。

一般事項について:

NSManagedObjectContext使用時に をロックするNSPersistentStoreCoordinatorので、PSC が 1 つだけでも問題ありません。

Core Data でのスレッド化のルールに従ってください。特に、それぞれNSManagedObjectContextは 1 つのスレッド (つまり、それを作成したスレッド) からのみアクセスできます。

詳細については、例を参照してください。

アップデート

あなたの問題はNSManagedObjectContext、間違ったスレッドからアクセスしていることだと確信しています。コンテキストを作成したのと同じスレッドからコンテキストにアクセスする必要があります。コードでこれを正しく行っていることを確認してください。

fetchEntity:を作成したのと同じスレッドからメソッドを呼び出していますNSManagedObjectContextか? そのコンテキストは、いつ、どのように作成されますか?

この質問と回答を参照してください: NSManagedObjectContext Locked

于 2013-03-11T11:01:47.160 に答える
0

同じ結果でしたが、別の問題がありました。既存のコアデータ アプリをマルチスレッド化しました。メインスレッド以外は何も使用していませんでした。

メインスレッドにいるかどうかに基づいて、使用するコンテキストを指定していました。dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND) のようなものを使用すると、メイン スレッドになる可能性があります (これは Apple の最適化です)。これにより、コンテキスト オブジェクトが混在し、デッドロックが発生しました。

于 2016-05-03T19:37:05.807 に答える