Note that there are some explanatory texts on larger screens.

plurals
  1. POCore Data - multi thread - race condition on startup
    primarykey
    data
    text
    <p>I have a multi-threaded app that uses Core Data. I've been seeing a lot of crashes on startup, and various bizarre error messages. However, sometimes it works fine! I have never seen a crash on my own iPhone4, but it does crash on other devices. I think I've figured out the issue, but am not sure how to best solve it.</p> <p>When the app starts, I use GCD to download data from the web and update core data on a background thread. On the main thread, I continue with setting up table views, and one of these commands triggers the <code>NSManagedObjectContext</code> getter. I'm using pretty much the standard template code, so as it is the first time this is run, the usual lazy instanciation code creates the <code>NSPersistentStoreCoordinator</code>. </p> <p>However the background thread is creating a new <code>NSManagedObjectContext</code> for it's own use. This includes getting the <code>NSPersistentStoreCoordinator</code> as follows:</p> <pre><code> // Create a new NSManagedObjectContext for this thread NSManagedObjectContext *threadContext = nil; NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; if (coordinator != nil) { threadContext = [[NSManagedObjectContext alloc] init]; [threadContext setPersistentStoreCoordinator:coordinator]; NSMergePolicy *mergePolicy = [[NSMergePolicy alloc] initWithMergeType:NSMergeByPropertyObjectTrumpMergePolicyType]; [threadContext setMergePolicy:mergePolicy]; } else { NSLog(@"Error - No NSPersistentStoreCoordinator"); } </code></pre> <p>I'm 90% sure that issue is that both threads are getting to the <code>NSPersistentStoreCoordinator</code> code at the same time. Both threads believe the object is <code>nil</code>, therefore create the object. This causes issues for the first thread to get there as the ivar suddenly points to the wrong place. At that point bad things happen!</p> <p>So how best to solve this? I have temporarily fixed the issue by adding a <code>sleep(1)</code> to the background thread :) but I'm not sure this is really the best solution! I have tried changing the <code>NSPersistentStoreCoordinator</code> properties so that they are atomic, but this hasn't helped. Should I wrap each of the standard getters in <code>@synchronise</code> to mutex lock them? I haven't had time to try this yet, but it should stop the same code being run by both threads. Or is there a better way?</p> <p>Thoughts?</p> <p>Thanks Craig</p> <p>======================================</p> <p>For info, here are some of the errors and crashes I have seen. These are pretty random, but it may help others find this post in the future.</p> <blockquote> <p>2012-01-18 22:19:57.586 CBF[10468:11d03] -[NSSQLModel _addPersistentStore:identifier:]: unrecognized selector sent to instance 0x6b80390</p> <p>2012-01-18 22:19:57.595 CBF[10468:11d03] <em>*</em> Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSSQLModel _addPersistentStore:identifier:]: unrecognized selector sent to instance 0x6b80390'</p> <p>2012-01-19 16:58:06.671 CBF[11738:fe03] -[__NSCFDictionary _hasPrecomputedKeyOrder]: unrecognized selector sent to instance 0x6d55040</p> <p>2012-01-25 21:45:31.174 CBF[16911:1310b] -[__NSArrayM _addPersistentStore:identifier:]: unrecognized selector sent to instance 0x6d59370</p> <p>2012-01-25 21:45:31.175 CBF[16911:1310b] <em>*</em> Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayM _addPersistentStore:identifier:]: unrecognized selector sent to instance 0x6d59370'</p> </blockquote>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload