11

In Obj-C, what does it mean in simple terms; "CoreData is not thread safe"

OR in general what is "not thread safe" ?

hmthur
  • 2,545
  • 3
  • 20
  • 18

2 Answers2

24

@d11wtq's answer is correct only when writing your own code or designing your own APIs.

It is entirely incorrect when working with a set of APIs and quite specifically wrong when working with Core Data.

In the context of working with Mac OS X and iOS, thread safety must always be considered in the context of working with the system APIs. Even using, say, an NSArray means that you are working with the system APIs.

OR in general what is "not thread safe" ?

A non-thread safe API is an API where you cannot interact with the API from multiple threads simultaneously. There may also be additional restrictions that most often involve the main thread. For example, almost all drawing operations must occur on the main thread on both Mac OS X and iOS.

The Apple documentation assumes thread safety is the exceptional case. That is, an API is only thread safe if the documentation explicitly claims thread safety. If there is no mention of thread safety, you must assume that the API is not thread safe.

In Obj-C, what does it mean in simple terms; "CoreData is not thread safe"

That statement is not quite correct, but it is a safe assumption.

In Core Data's case, the thread interaction behavior is extremely well documented.

In short, parts of the API are thread safe (the store coordinator, for example) and parts are quite explicitly not thread safe. While the MOC provides lock and unlock methods, you can also use external locking. But don't. It will be less efficient and more fragile; significantly so. In general, don't use the internal locking either. CoreData is optimized around having a context per thread/queue.

(Answer fixed based on TC's feedback. Thanks.)

bbum
  • 162,346
  • 23
  • 271
  • 359
  • 1
    NSArray doesn't explicitly say it's thread safe at least no in the class documentation at http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/NSArray.html and yet it's pretty common to use an NSMutableArray with an NSLock to protect access to it by multiple threads. Is this then not "safe" usage? – Dad Dec 28 '10 at 19:39
  • NSArray is a border case; *technically* no amount of locking will make it thread safe. *Realistically* the implementation is isolated to the point of lock encapsulation being "safe enough". The issue, though, is that you have to make sure that **every single** method invocation on that array is behind your locks; you can't let the array escape into framework code, for example. – bbum Dec 28 '10 at 19:45
  • Interestingly enough, the word "thread" doesn't appear in "Collections Programming Guide" ( http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Collections/Collections.html%23//apple_ref/doc/uid/10000034i ) and "safe" only appears once and is talking about enumeration and modifying the collection during enumeration (not safe). – Dad Dec 28 '10 at 19:50
  • Ah, the point about not letting the NSArray instance escape into framework code is an *excellent* one and something I'm sure I've seen code fail to consider. – Dad Dec 28 '10 at 19:51
  • We are both entirely wrong about NSArray, btw. http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Multithreading/ThreadSafetySummary/ThreadSafetySummary.html NSArray is specifically listed as being thread safe (this is relatively new in the history of NSArray). I'd delete my comment if I could. :) – bbum Dec 28 '10 at 19:57
  • NSMutableArray, though, is **not thread safe** and, thus, the comments above would apply to it! – bbum Dec 28 '10 at 20:00
  • Funny that even 31.2K reputation doesn't let you delete your *own* comments. :-) – Dad Dec 28 '10 at 20:35
  • @Dad: Hm? I can delete my own comments no problem. I don't think it comes at 35k or whatever. Only thing I can't do to them after 5 minutes is edit. – Peter Hosey Dec 29 '10 at 09:36
  • Oh -- der -- there it is. I'll let 'em stand as monument to my overlooking the obvious (and because, ultimately, it is a useful exchange) – bbum Dec 29 '10 at 21:16
  • -1. Documentation explicitly states that NSManagedObjectContext is thread-safe and its objects are thread-safe provided that all access to the context or its objects occur while holding the lock, and recommends -lock and -unlock for these purposes (while implying that any lock will do). – tc. Apr 06 '11 at 21:23
  • @tc If you have to hold an exclusive lock when access API, then that API is inherently not thread safe. And that is exactly what is going on with NSMOC; the API is *not* thread safe externally, but it *does* provide a means of exclusion (unlike, say, NSView which is neither thread safe nor provides a means of exclusion). If you *don't* use NSMOC's `lock` and `unlock` methods, you are in for a world of hurt; it won't work. – bbum Apr 06 '11 at 22:36
  • To quote the manual: "If you share a managed object context or a persistent store coordinator between threads, you must ensure that any method invocations are made from a thread-safe scope. For locking, you should use the **NSLocking methods on managed object context** and persistent store coordinator instead of implementing your own mutexes." **Emphasis** mine. – bbum Apr 06 '11 at 22:40
  • Should, not must, and the WWDC 2010 session seemed to imply that any lock will do. – tc. Apr 06 '11 at 23:11
  • Also, "thread-safe" is a fairly useless term on its own - thread-safety is always with respect to certain usage patterns (it definitely doesn't mean "free from potential concurrency issues"). For example, atomic properties are guaranteed to be atomic but (IIRC) aren't necessarily serialized. – tc. Apr 06 '11 at 23:22
  • OK -- yes -- I read the source. You are technically correct. If you want to maximize inefficiency and fragility, you can use external locking. Answer updated. But, really, don't do that. – bbum Apr 06 '11 at 23:38
4

UPDATE | Please see @bbum's answer. I accept that my answer is flawed and @bbum is correct.

If something is described as "not thread safe", it means that no special precautions have been taken to ensure it won't crash should two separate threads try to use it simultaneously. In general, code that is to be used by more than one thread requires explicit locks (or @synchronize blocks) wrapping around aspects of the code. In particular, any object/variable that will be modified would almost certainly cause a crash if two threads happened to write to it at the same time (since they'd be writing to the same memory address). Similarly, if one thread was reading a variable while another was writing to it, garbage would be returned and the program would likely crash.

Using @synchronized, or NSLock or a POSIX mutex etc, ensures that only one thread can execute a particular block of code at any given time. The other threads get blocked and have to wait until the lock is released. There is a slight performance hit with using locks (and of course some development overhead having to think about them), so often code expressly declares that it is not thread safe, leaving you, the adopter of the code, to place locks as needed yourself (or limit execution of the non thread-safe to a single thread).

See the Apple documentation for more information about threading and thread safety:

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocThreading.html#//apple_ref/doc/uid/TP30001163-CH19-BCIIGGHG

d11wtq
  • 34,788
  • 19
  • 120
  • 195
  • 4
    *Using @synchronized, or NSLock or a POSIX mutex etc, ensures that only one thread can execute a particular block of code at any given time.* In the context of the question this is **entirely wrong**. You cannot use any amount of locking to ensure that a thread unsafe API is made thread safe! – bbum Dec 28 '10 at 17:59
  • 1
    The problem, more specifically, is that any of those only ensures that *that* block only runs on one thread at a time. It does not ensure anything about any *other* block that may also use the unsafe API. If two different parts of your program—or your program and the implementation of another API you use—both access the unsafe API, bad things happen no matter how many locks you put in. – Peter Hosey Dec 28 '10 at 18:47
  • Thanks guys, I've certainly learned something here. @hmthur should accept @bbum's answer instead. – d11wtq Dec 28 '10 at 22:18