Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unexpected Core Data Multithreading Violation

I'm using Apple's concurrency core data debugger.

-com.apple.CoreData.ConcurrencyDebug 1

From time to time I got __Multithreading_Violation_AllThatIsLeftToUsIsHonor__, even I'm almost sure threading is not violated.

This is part of code where exception occurs (code is part of protocol that extends NSManagedObject):

public static func find(arrayBy predicate: NSPredicate, sort: [NSSortDescriptor] = [], limit: Int? = nil) -> [Self] {
    let fetchRequest = NSFetchRequest<Self>(entityName: "\(Self.self)")
    fetchRequest.predicate = predicate
    fetchRequest.sortDescriptors = sort

    do {
        return try Context.current.fetch(fetchRequest) // Exception!!!
    } catch let error {
        Logger.fatal("Failed to perform fetch: \(error)")
        return []
    }
}

Code is executed within context's perform: block.

Here is thread information:

enter image description here

and debuger info to confirm that perform is executed on the right NSManagedContext:

(lldb) po Context.current
<StoreContext: 0x7f854b556610>

Entity name is extracted successfully:

po fetchRequest.entityName!
"Position"

Predicate is constructed of pure String objects (no managed objects used at all):

(lldb) po fetchRequest.predicate!
ANY employees.company.id == "282372"

Sort descriptors are not used at all in this case:

po fetchRequest.sortDescriptors!
0 elements

Limit is completely ignored.

What am I missing? Does anyone has any idea what can be wrong here?

Edit:

To clarify, Context.current is set just before dispatching the block:

Context.current = managedObjectContext
managedObjectContext.performAndWait {
   //...
}

You can see on the screenshot that Thread 13 is running on Queue: NSManagedObject 0x7f854b556610 (serial). Also, when exception occurs Context.current returns <StoreContext: 0x7f854b556610>. By looking at the memory address it's easy to conclude block is executing on the right queue.

like image 356
XeNoN Avatar asked Feb 02 '17 10:02

XeNoN


1 Answers

Storing the "current" background context in a global state is a bad practice. I can't point out where exactly in your code it is messing up, but unexpected things can happen with global state when multithreading is involved. Change your find function to accept a context as a parameter. This will avoid using any global state and is will likely fix your problem.

like image 147
Jon Rose Avatar answered Sep 18 '22 16:09

Jon Rose