We are experiencing the following crash
realm::Realm::verify_thread() const (shared_realm.cpp:274)
It happens sporadic but from different flows in our code.
One of the stacktraces we find is
0x00000001003af7ec realm::Realm::verify_thread() const (shared_realm.cpp:274)
0x0000000100339d78 RLMGetObjects (RLMObjectStore.mm:83)
0x0000000100330130 +[RLMObject objectsWithPredicate:] (RLMObject.mm:150)
0x00000001000fa468 -[PrinterRepository getDefaultPrinter] (PrinterRepository.m:35)
0x00000001001faf3c -[PrintService handlePrintJobs] (PrintService.m:106)
Our code in [PrinterRepository getDefaultPrinter] is
return [[Printer objectsWithPredicate:[NSPredicate predicateWithFormat:#"isDefault == 1"]] firstObject];
Locally we aren't able to reproduce this yet, we've only seen this happen from time to time with our beta testers.
Our realm version is 0.102.1
Our iOS versions are 9.2.1, 9.3.2 & 9.3.3
Does someone has an idea of the cause of this crash?
Managed Realm objects are thread confined. You're not allowed to pass them around arbitrarily between threads. When you retrieve an object on the main thread, you're only allowed to use it there. When you want to pass it to a background thread, you will need to retrieve on the main thread an identifier, ideally the property designated as primaryKey, and pass that over to the background thread.
You get a failure like that whenever you violate against that.
See our the relevant chapter of our docs about "Passing Instances Across Threads":
Unmanaged instances of RLMObjects behave exactly as regular NSObject subclasses, and are safe to pass across threads.
Instances of RLMRealm, RLMResults, or RLMArray, or managed instances of RLMObject can only be used on the thread on which they were created, otherwise an exception is thrown*. This is one way Realm enforces transaction version isolation. Otherwise, it would be impossible to determine what should be done when an object is passed between threads at different transaction versions without a potentially extensive relationship graph.
Instead, there are several ways to represent instances in ways that can be safely passed between threads. For example, an object with a primary key can be represented by its primary key’s value; or an RLMResults can be represented by its NSPredicate or query string; or an RLMRealm can be represented by its RLMRealmConfiguration. The target thread can then re-fetch the RLMRealm, RLMObject, RLMResults, or RLMArray using its thread-safe representation. Keep in mind that re-fetching will retrieve an instance at the version of the target thread, which may differ from the originating thread.
Related
I've come across an interesting issue using mutable dictionaries on background threads.
Currently, I am downloading data in chunks on one thread, adding it to a data set, and processing it on another background thread. The overall design works for the most part aside from one issue: On occasion, a function call to an inner dictionary within the main data set causes the following crash:
*** Collection <__NSDictionaryM: 0x13000a190> was mutated while being enumerated.
I know this is a fairly common crash to have, but the strange part is that it's not crashing in a loop on this collection. Instead, the exception breakpoint in Xcode is stopping on the following line:
NSArray *tempKeys = [temp allKeys];
This leads me to believe that one thread is adding items to this collection while the NSMutableDictionary's internal function call to -allKeys is enumerating over the keys in order to return the array on another thread.
My question is: Is this what's happening? If so, what would be the best way to avoid this?
Here's the gist of what I'm doing:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
for (NSString *key in [[queue allKeys] reverseObjectEnumerator]) { //To prevent crashes
NEXActivityMap *temp = queue[key];
NSArray *tempKeys = [temp allKeys]; //<= CRASHES HERE
if (tempKeys.count > 0) {
//Do other stuff
}
}
});
You can use #synchronize. And it will work. But this is mixing up two different ideas:
Threads have been around for many years. A new thread opens a new control flow. Code in different threads are running potentially concurrently causing conflicts as you had. To prevent this conflicts you have to use locks like #synchronized do.
GCD is the more modern concept. GCD runs "on top of threads" that means, it uses threads, but this is transparent for you. You do not have to care about this. Code running in different queues are running potentially concurrently causing conflicts. To prevent this conflicts you have to use one queue for shared resources.
You are already using GCD, what is a good idea:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
The same code with threads would look like this:
[[NSThread mainThread] performSelector:…];
So, using GCD, you should use GCD to prevent the conflicts. What you are doing is to use GCD wrongly and then "repair" that with locks.
Simply put all accesses to the shared resource (in your case the mutable dictionary referred by temp) into on serial queue.
Create a queue at the beginning for the accesses. This is a one-timer.
You can use one of the existing queues as you do in your code, but you have to use a serial one! But this potentially leads to long queues with waiting tasks (in your example blocks). Different tasks in a serial queue are executed one after each other, even there are cpu cores idle. So it is no good idea to put too many tasks into one queue. Create a queue for any shared resource or "subsystem":
dispatch_queue_t tempQueue;
tempQueue = dispatch_queue_create("tempQueue", NULL);
When code wants to access the mutable dictionary, put it in a queue:
It looks like this:
dispatch_sync( tempQueue, // or async, if it is possible
^{
[tempQueue setObject:… forKey:…]; // Or what you want to do.
}
You have to put every code accessing the shared resource in the queue as you have to put every code accessing the shared resource inn locks when using threads.
From Apple documentation "Thread safety summary":
Mutable objects are generally not thread-safe. To use mutable objects
in a threaded application, the application must synchronize access to
them using locks. (For more information, see Atomic Operations). In
general, the collection classes (for example, NSMutableArray,
NSMutableDictionary) are not thread-safe when mutations are concerned.
That is, if one or more threads are changing the same array, problems
can occur. You must lock around spots where reads and writes occur to
assure thread safety.
In your case, following scenario happens. From one thread, you add elements into dictionary. In another thread, you accessing allKeys method. While this methods copies all keys into array, other methods adds new key. This causes exception.
To avoid that, you have several options.
Because you are using dispatch queues, preferred way is to put all code, that access same mutable dictionary instance, into private serial dispatch queue.
Second option is passing immutable dictionary copy to other thread. In this case, no matter what happen in first thread with original dictionary, data still will be consistent. Note that you will probably need deep copy, cause you use dictionary/arrays hierarchy.
Alternatively you can wrap all points, where you access collections, with locks. Using #synchronized also implicitly create recursive lock for you.
How about wrapping where you get the keys AND where you set the keys, with #synchronize?
Example:
- (void)myMethod:(id)anObj
{
#synchronized(anObj)
{
// Everything between the braces is protected by the #synchronized directive.
}
}
For an object shared between threads (via persisting and querying), will changes to an ignored property made in one thread be visible in another thread?
To share objects between threads or re-use them between app launches you must persist them to a Realm ... all changes you make to it will be persisted (and must be made within a write transaction). Any changes are made available to other threads that use the same Realm when the write transaction is committed.
http://realm.io/docs/cocoa/0.91.1/#writes
It looks like this doesn't apply to ignored properties. Each thread's instance of the object has its own copy of the ignored property, and changes in one thread don't affect any other threads. Is that right?
Correct. When you access an RLMObject from another thread by re-querying for it, it will be a new instance of the object, so the ignored properties will not be carried along with that one.
That being said, as long as you don't try and access any of the Realm-backed properties (Else a RLMException will be triggered), you CAN pass an RLMObject instance from one thread to another and still continue to access its ignored properties on the new thread.
According to Using Swift with Cocoa and Objective-C you can use takeUnretainedValue() and takeRetainedValue()to tell Swift how to manage the memory of an object for a function like this:
func StringByAddingTwoStrings(CFString!, CFString!) -> Unmanaged<CFString>!
When do I have to use takeUnretainedValue() or takeRetainedValue()?
When I use ARC is it then always takeUnretainedValue()?
You use takeRetainedValue when the unmanaged object has a +1 retain count and you want ARC to take care of releasing the object when you're done. For example, if you call a Core Foundation function with Create or Copy in the name (see Create Rule in the Memory Management Programming Guide for Core Foundation) which returns an unmanaged object for which you are responsible for releasing, you generally use takeRetainedValue so that it is released for you (or, if you don't do this, you have to manually release it yourself with CFRelease or similar function). You use takeUnretainedValue when ownership of the object has not been transferred to you and you therefore do not want ARC releasing the object for you when it falls out of scope.
So, as to when you call takeUnretainedValue vs takeRetainedValue, it simply depends upon what sort of object the called function returns. As a general rule of thumb, if the object was returned from a Core Foundation function with Create or Copy in the name, use takeRetainedValue. Otherwise use takeUnretainedValue.
In terms of what happens if you call the wrong method, if you call takeUnretainedValue when you're passed a +1 object (e.g. an object returned from Core Foundation function with Create or Copy in the name), your app will leak unless you explicitly CFRelease it. You may not immediately notice the occasional leak when running the app, but it can be observed by watching your app's memory usage (e.g. if you profile your app with Instruments). But if you leave these leaks unresolved, your app may eventually receive memory warnings.
On the other hand, if you call takeRetainedValue on an object which has not been retained for you (returned by a function that did not have Create or Copy in its name), the app will likely crash when the object is released. Sometimes this won't manifest itself immediately (not until the last strong reference is resolved), but it will generally result in a catastrophic failure of the app.
So judicious selection of takeUnretainedValue vs takeRetainedValue is very important.
Quoting from NSHipster:
https://nshipster.com/unmanaged/
An Unmanaged instance wraps a CoreFoundation type T, preserving a reference to the underlying object as long as the Unmanaged instance itself is in scope. There are two ways to get a Swift-managed value out of an Unmanaged instance:
takeRetainedValue() returns a Swift-managed reference to the wrapped instance, decrementing the reference count while doing so—use with the return value of a Create Rule function.
takeUnretainedValue() returns a Swift-managed reference to the wrapped instance without decrementing the reference count—use with the return value of a Get Rule function.
In order to avoid race conditions around Core Data, different threads should use different NSManagedObjectContexts (see e.g. here).
To ensure this at runtime I would like to assert before each use of a managed object context that the same thread (or operation queue) is current as was when the managed object context was created. In effect, I would like to assert something like NSThread.currentThread == storedThread (or NSOperationQueue.currentQueue == storedQueue).
Is it appropriate to check for pointer equality between threads (or operation queues) for the stated purpose? And is there a semantic difference between comparing threads and operation queues, again for this stated purpose? (The Apple documentation for frameworks such as Core Data and UIKit usually explains situations around race conditions in terms of threads, e.g.: "Create a separate managed object context for each thread and share a single persistent store coordinator.")
UPDATE I've by now learned (from revisiting WWDC 2012 Session 2014 Core Data Best Practices) that using a NSManagedObjectContext with NSPrivateThreadConcurrencyType will probably solve this and is the way to go. However, the question would still seem to apply to the legacy choice NSConfinedConcurrencyType.
UPDATE From the WWDC 2014 session on What's new in Core Data: the launch argument -com.apple.CoreData.ConcurrencyDebug 1 is by now also supported on iOS and implies pretty much the same assertions that I was aiming at (see here).
It is my understanding that isExecuting just indicates that the thread hasn't been cancelled or finished. As a result, more than one thread will be isExecuting at a time.
Your == comparison is the one to do.
Relying on Core Data's own assertions turned out to be the way to go (see updated question). By relying on the I no longer need to compare for equality of threads (or other abstractions of "threads") at the application level.
I understand why this error happens: when you try to access a CoreData object that was deleted in a managed object context on another thread, and is hence set to a 'fault' object, and any retained references will therefore no longer point to a valid CoreData object.
I am using a NSFetchedResultsController.
I have confirmed that all the code is implemented correctly. I have 2 managed object contexts, one intended for a BG thread and one for the main thread.
I have confirmed that the main thread is subscribed for notifications under NSManagedObjectContextDidSaveNotification.
I have confirmed that when this notification fires, I perform a mergeChangesFromContextDidSaveNotification: on the main thread managed object context.
I am NOT retaining these objects anywhere, but I am setting the batch size for the NSFetchRequest (Is this potentially the issue?)
YET, I still occasionally get the 'CoreData could not fulfill a fault' error.
In my particular application, this usually happens during a sort of "data-bind" process so I could safely just discard fault objects and move on. I would like to do this by wrapping the inside of the loop that data-binds in a #try-catch block and just skip rows that I get the CoreData error for.
Can I safely do this with CoreData? Or do I need to completely dump the managed object context after I encounter a fault.
I did check this question about how to check if a CoreData object is a fault, which might be something I implement if I can't safely assume that my #try-catch block won't cause other issues.
Instead of using try-catch we can use "existingOjectWithId" and check for nil on returned object.
- (NSManagedObject*)existingObjectWithID:(NSManagedObjectID*)objectID error:(NSError**)error
The above returns the object for the specified ID if it is already registered in the context, or faults the object into the context. If the object cannot be fetched, or does not exist, or cannot be faulted, it returns nil. Unlike -objectWithID: it never returns a fault.