2013-03-11 100 views
1

我正在做2核心數據提取,當他們在大約同一時間執行時,他們將導致主線程死鎖,導致我的應用程序凍結。核心數據死鎖

提取是在主線程中進行的。處理這種情況的一種方法是確保提取不是在同一時間進行的,但我無法控制提取何時完成。有沒有其他辦法可以避免這種僵局?

堆棧追蹤暫停應用程序時是:

#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塊內請求(如本post建議)和到目前爲止,它似乎工作得很好......我正在訪問我的MOC正確的線程上。MOC初始化爲_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];

+1

? – 2013-03-11 10:02:58

+0

@RajanBalana沒有理由......會在後臺線程中運行提取幫助嗎?它們不會死鎖麼? – 2013-03-11 10:16:17

+0

「使用後臺線程」不是一種神奇的修復方法。在給出Core Data使用情況下,BG線程可能是合適的,但我們可以我們不知道目前所知道的是什麼 – occulus 2013-03-11 11:09:13

回答

5

這聽起來像是問題出在您的應用程序的線程/互斥/邏輯(或缺乏)圍繞想要同時使用Core Data的代碼的相關部分。

往往被忽視的線程的規則:

在語言或API使用線程結構並不一定意味着你的代碼是線程安全的!

沒有看到您的代碼和邏輯,很難說更多。訪問Core Data試圖做的不同部分是什麼?

作爲一般策略,解決死鎖的方法可能是將違規的Core Data訪問代碼收集到僅管理核心數據訪問的控制器對象中。它可以負責避免代碼拋出的任何死鎖狀態。

在一般事項:

NSManagedObjectContext鎖定NSPersistentStoreCoordinator當它使用它,所以僅具有一個PSC不應該是一個問題。

請確保遵循核心數據線程的規則。特別是,每個NSManagedObjectContext只能從一個線程訪問 - 即創建它的線程。

更多的討論,參見例如:

更新

我敢肯定你的親瑕疵是你從錯誤的線程訪問NSManagedObjectContext。您必須從創建它的相同線程訪問上下文。請確認您在代碼中正確執行此操作。

您確定要從創建NSManagedObjectContext的同一個線程調用您的fetchEntity:方法嗎?這個上下文是如何創建的?何時創建?

看到這個問題,回答:NSManagedObjectContext Locked

+0

訪問核心數據的不同部分試圖執行一個獲取請求,他們都調用這個方法:'NSArray * reminders = [[CoreDataHelper sharedInstance] fetchEntity:APReminderEntity謂詞:nil和SortDescriptors: [NSArray arrayWithObject :dateAscendingDescriptor] inManagedObjectContext:nil];' – 2013-03-11 12:38:05

+0

嗨,彼得,請將您的問題的解釋添加到最顯眼的地方,而不是作爲評論! – occulus 2013-03-11 12:39:48

+0

你需要展示你的CoreDataHelper在做什麼。 – occulus 2013-03-11 12:40:19

0

我有同樣的結果,但不同的問題。我有一個已經存在的coredata應用程序多線程。它只使用主線程。

我正在指定使用哪個上下文,基於我是否在主線程上。使用類似dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND 可以把你在主線程(這是一個蘋果的優化)。這使得你爲什麼沒有在後臺線程執行取我的混合環境中的物體並導致死鎖