Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is a GCD dispatch queue enough to confine a Core Data context to a single thread

I'm beginning to think the answer to my question is 'No', but I'm still confused and uncertain about this. So please confirm. I've already learned the need to be careful when using Core Data with multiple threads. NSManagedObjectContext objects must not cross thread boundaries. Being a newbie with both threads and Core Data, I happily found that GCD should make some of this easier.

Naively perhaps, I then thought I would simply create a dedicated GCD dispatch queue for dealing with Core Data (or even, if needed, have multiple dispatch queues each with its own core data context). That would have been simple.

But now I realize that one big advantage of GCD dispatch queues is that it manages and makes use of multiple threads as needed. So - if I understand this right - tasks I hand off to one and the same dispatch queue, could end up running in different threads, potentially handing off a core data context from one thread to another, and having things go wrong. Is that right?

I've read many related questions and answers, for example Core Data and threads / Grand Central Dispatch, but I remain somewhat confused. The accepted answer to that question, using GCD queues, does ensure that a new context is created on each thread, but does not point out the necessity of doing this. Another answer says "You could execute all CoreData work on a queue named com.yourcompany.appname.dataaccess" seeming to imply that as long as the Core Data work is confined to one GCD dispatch queue, then all is OK. Maybe it is not.

like image 332
rene Avatar asked Oct 10 '11 21:10

rene


People also ask

Is GCD thread safe?

In apple document, GCD is Thread-Safe that means multiple thread can access.

How many types of dispatch queues are there?

There are two types of dispatch queues, serial dispatch queues and concurrent dispatch queues.

Is DispatchQueue global serial or concurrent?

The main dispatch queue is a globally available serial queue executing tasks on the application's main thread. As the main thread is used for UI updates it's important to be conscious when executing tasks on this queue.

What is DispatchQueue global in Swift?

An object that manages the execution of tasks serially or concurrently on your app's main thread or on a background thread. iOS 8.0+ iPadOS 8.0+ macOS 10.10+ Mac Catalyst 13.0+ tvOS 9.0+ watchOS 2.0+ Xcode 8.0+


1 Answers

Update: As @adib points out in a comment, the approach to serialized managed object context access has changed in iOS 9 and MacOS X 10.11. NSConfinementConcurrencyType, the thread confinement strategy, is now deprecated in favor of NSPrivateQueueConcurrencyType and NSMainQueueConcurrencyType. In other words, stop using threads for concurrent access to Core Data objects and instead start using GCD. You should use either the main dispatch queue or the one associated with the MOC, depending on how you configure the MOC, and not a queue of your own creation. This is easy to do using NSManagedObject's -performBlock: or -performBlockAndWait: methods.


Short answer: Using a serial dispatch queue can provide serialized access to a managed object context, and that's an acceptable way to implement the "thread confinement" strategy even though GCD may actually employ multiple threads.

Longer answer:

The accepted answer to that question, using GCD queues, does ensure that a new context is created on each thread, but does not point out the necessity of doing this.

The big thing you need to remember is that you must avoid modifying the managed object context from two different threads at the same time. That could put the context into an inconsistent state, and nothing good can come of that. So, the kind of dispatch queue that you use is important: a concurrent dispatch queue would allow multiple tasks to proceed simulaneously, and if they both use the same context you'll be in trouble. If you use a serial dispatch queue, on the other hand, two or more tasks might execute on different threads, but the tasks will be executed in order, and only one task will run at a time. This is very similar to running all the tasks on the same thread, at least as far as maintaining the context's consistency goes.

See this question and answer for a much more detailed explanation.

This is how Core Data has always worked. The Concurrency with Core Data section of the Core Data Programming Guide gives advice on how to proceed if you do decide to use a single context in multiple threads. It talks mainly about the need to be very careful to lock the context any time you access it. The point of all that locking, though, is to ensure that two or more threads don't try to use the context simultaneously. Using a serialized dispatch queue achieves the same goal: because only one task in the queue executes at a time, there's no chance that two or more tasks will try to use the context at the same time.

like image 82
Caleb Avatar answered Sep 23 '22 05:09

Caleb