CoreData: обновление в фоновом режиме и чтение в основном потоке вызывает мертвую блокировку - PullRequest
6 голосов
/ 22 ноября 2011

Я отображаю таблицу с некоторыми данными для пользователя. Как только представление представлено, я делаю веб-вызов, чтобы узнать, есть ли обновленные данные (асинхронно). Когда сервисный вызов вернется, я бы хотел обновить свои основные данные и представление.

К сожалению, я часто получаю мертвые блокировки, потому что представление считывает те же данные, что и сервисный вызов. Как я могу решить это?

Когда я приостанавливаю симулятор, как только он заморожен, ожидающие потоки ожидают в следующих местах:

Фоновая (обновляемая) тема: (psynch_cvwait)

[mainContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:)
                              withObject:notification
                           waitUntilDone:YES];

Основная тема: (psynch_mutexwait) выполняя filteredArrayUsingPredicate

Большое спасибо!

Ответы [ 3 ]

8 голосов
/ 23 ноября 2011

-mergeChangesFromContextDidSaveNotification: заблокирует основной поток.Этот вызов блокирует оба экземпляра NSManagedObjectContext, в то время как он обновляет основной контекст, передавая изменения.

Это обычно считается неизбежным в приложениях, предшествующих iOS 5.Вы можете свести его к минимуму, делая более частые, менее масштабные сохранения, но это все еще произойдет.

Единственный другой вариант для приложений до iOS 5 - это указание основного контекста -reset:, но для этого потребуетсяповторная загрузка всего - еще одна задержка.

2 голосов
/ 22 ноября 2011

Похоже, что основной поток пытается захватить некоторую низкоуровневую блокировку, которую уже имеет фоновый поток (или наоборот). Вы используете @synchronized где-нибудь для предоставления мьютекса?

В любом случае, есть ли причина, по которой ваш фоновый поток должен ждать завершения -mergeChangesFromContextDidSaveNotification:? Если нет, передайте NO в качестве последнего параметра.

0 голосов
/ 19 ноября 2016

У меня была такая же проблема (блокировка на psynch_cvwait), когда я сливал изменения контекста (оба пути) между основным и фоновым контекстом (оба с использованием NSConfinementConcurrencyType). Проблема была вызвана подпиской на NSManagedObjectContextDidSaveNotification в другой очереди, из которой она была отправлена:

[[NSNotificationCenter defaultCenter]
addObserverForName:NSManagedObjectContextDidSaveNotification
object:mainContext
queue:bgQueue
usingBlock:^(NSNotification * _Nonnull note) {
  // bgContext runs on bgQueue
  [bgContext mergeChangesFromContextDidSaveNotification:note];
}]

В результате блок никогда не вызывался, и основная и фоновая очереди зависали на psynch_cvwait()

Я исправил это, не блокируя очередь mainContext:

[[NSNotificationCenter defaultCenter]
addObserverForName:NSManagedObjectContextDidSaveNotification
object:mainContext
queue:nil
usingBlock:^(NSNotification * _Nonnull note) {
    [bgQueue addOperationWithBlock:^{
        [bgContext mergeChangesFromContextDidSaveNotification:note];
    }];
}]

Однако, если я блокирую фоновую очередь при объединении изменений в основной контекст, то, похоже, это не проблема.

...