CoreData: updating in the background and reading in the main thread causes a deadlock

I am showing a table with some data for the user. Once the presentation is presented, I make a web call to see if the data is updated (asynchronously). When the service call returns, I would like to update the master data and view.

Unfortunately, I often get deadlocks because the view reads the same data as the service call record. How can i solve this?

When I pause the simulator immediately after it is frozen, waiting threads are waiting in the following places:

Background (update) stream: (psynch_cvwait)

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

Main topic: (psynch_mutexwait) doing filteredArrayUsingPredicate

Thanks a lot!

+6
source share
3 answers

-mergeChangesFromContextDidSaveNotification: will block the main thread. This call blocks both instances of NSManagedObjectContext while it updates the main context with the changes being propagated.

This is usually considered unavoidable in pre-iOS 5 applications. You can minimize it by making more frequent, smaller, savings, but it will happen anyway.

The only other option for applications pre-iOS 5 is to specify the basic context on -reset: , but it will take repeated sample - another delay.

+8
source

It appears that the main thread is trying to capture the lower level lock that the background thread already has (or vice versa). Do you use @synchronized anywhere to provide a mutex?

In any case, is there a reason your background thread should wait for -mergeChangesFromContextDidSaveNotification: to finish? If not, skip NO as the last parameter.

+2
source

I had the same problem (lock on psynch_cvwait) when I changed context changes (in both directions) between the main and background context (both using NSConfinementConcurrencyType ). The problem was caused by subscribing to NSManagedObjectContextDidSaveNotification in another queue from which it was sent:

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

As a result, the block was never called, and both main and background queues hung on psynch_cvwait()

I fixed it without blocking the mainContext queue:

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

However, this does not seem to be a problem if I block the background queue when merging changes into the main context.

0
source

Source: https://habr.com/ru/post/902101/


All Articles