Is this a memory management problem when using multiple threads? - iphone

Example: In my main thread (the thread that's just there without doing anything special) I call a selector to be performed in a background thread. So there's a new thread, right? And now, inside this background thread I create a new object which holds image data. Next I use that object and want to keep it around for a while. How would I store a reference to that object so I can release it later? Or will the thread be alive as long as this object exists? How does a thread relate to objects which were created in it?
Maybe someone can explain this in clear words :-)

Storage location and thread creation are two separate concepts. It doesn't matter which thread created an object in terms of who will finally 'own' it or when it will be released later.
Unfortunately, there's no clear-cut answer to your question, but I'd start by thinking about whether this object is a singleton, or whether it's a cache item that can be purged, or whether it's a result object that you need to pass back to some other selector asynchronously.
If it's a singleton, put it in a static var, and never release it (or, consider doing so in response to a low memory warning)
If it's a cache, then have the cache own the item when it's inserted, so you don't have to worry about it. You might need an autorelease to do this, but be careful when using autorelease and threads since each thread may have its own autorelease pool which gets drained at different times.
If it's an object that you need to pass back to another caller, you want to autorelease it as you return and let the caller pick up the ownership of the item.

Related

Prevent a Race Condition using dispatch_sync

I am having a race condition with a NSManagedObjectContext. I was trying out various ways to prevent this using lock on NSManagedObjectContext. Using dispatch_sync seems to be a better approach as suggested by apple. But I am unable to figure out whether an object(being used under a block which is executed using dispatch_sync) can be saved from being accessed by two different threads.
Here is a more clear picture of what I am trying to ask:
[[*Some Singleton class* instance].managedObjectContext executeFetchRequest:request error:&err];
// After fetching results do something in DB
Let's say the above code is passed in a block executed using dispatch_sync like this:
dispatch_sync(someConcurrentQueue, ^{
[[*Some Singleton class* instance].managedObjectContext executeFetchRequest:request error:&err];
// After fetching results do something in DB
});
Can any other thread access [Some Singleton class instance].managedObjectContext before this block is completely executed.
AFAIK it can be accessed. If this is true then, is applying lock on NSManagedObjectContext the only way to prevent this race condition?
As always: It depends
dispatch_sync (and it's even safer cousin dispatch_barrier_sync) cause the queue it's called from to synchronously execute the block. In doing so, they block the thread. This makes one case potentially safe: access from the same thread. What you have to worry about in this scenario is that any reads you do may take place before the block is executed on the queue. Plan accordingly.
But this is ignoring a huge flaw in your code. Managed object contexts should never be shared across threads, or even dispatched off to a different thread from the one they were created on. You can fix your concurrent access problems by simply spawning child contexts.

how objects values are retained when we drain the pool at the end of run loop

I know this sounds like a dumb question but I need to ask this. Well I read that autorelease pool is drained after one iteration of run loop after it has handled events. My question is that then how come my apps objects are retained after I clicked on button. So, by definition It should destroy all the objects which I have created (may be I have assigned some values to objects) after I click on button. But that doesnt happen ? right ? I can click my button again and again but I dont lose any object data.
Correct me if I am wrong somewhere.
You should watch a video or two from https://developer.apple.com/videos/ - Great introductions to memory management and such. And I also strongly recommend you look into ARC as soon as you grasp the basics of retain/release/autorelease.
All that the autorelease pool does is decrement the retain count of objects in the pool when it is drained. If that results in the retain count becoming zero, the object will be destroyed (dealloc'ed).
However, if an object has been retained more than once, the retain count will be greater than zero so it will not be destroyed (note that objects are created with a retain count of 1.)

iOS5 NSManagedObjectContext Concurrency types and how are they used?

Literature seems a bit sparse at the moment about the new NSManagedObjectContext concurrency types. Aside from the WWDC 2011 vids and some other info I picked up along the way, I'm still having a hard time grasping how each concurrency type is used. Below is how I'm interpreting each type. Please correct me if I'm understanding anything incorrectly.
NSConfinementConcurrencyType
This type has been the norm over the last few years. MOC's are shielded from each thread. So if thread A MOC wants to merge data from Thread B MOC via a save message, thread A would need to subscribe to thread B's MOC save notification.
NSPrivateQueueConcurrencyType
Each MOC tree (parent & children MOCs) share the same queue no matter what thread each is on. So whenever a save message from any of these contexts is sent, it is put in a private cue specifically made only for this MOC tree.
NSMainQueueConcurrencyType
Still confused by this one. From what I gather it's the like NSPrivateQueueConcurrencyType, only the private queue is run on the main thread. I read that this is beneficial for UI communications with the MOC, but why? Why would I choose this over NSPrivateQueueConcurrencyType? I'm assuming that since the NSMainQueueConcurrencyType is executed in the main thread, does this not allow for background processes? Isn't this the same as not using threads?
The queue concurrency types help you to manage mutlithreaded core data:
For both types, the actions only happen on the correct queue when you do them using one of the performBlock methods. i.e.
[context performBlock:^{
dataObject.title = #"Title";
[context save:nil]; // Do actual error handling here
}];
The private queue concurrency type does all it's work in a background thread. Great for processing or disk io.
The main queue type just does all it's actions on a UIThread. That's neccesary for when you need to
do things like bind a NSFetchedResultsController up to it, or any other ui related tasks that need to be interwoven with processing that context's objects.
The real fun comes when you combine them. Imagine having a parent context that does all io on a background thread that is a private queue context, and then you do all your ui work against a child context of the main queue type. Thats essentially what UIManagedDocument does. It lets you keep you UI queue free from the busywork that has to be done to manage data.
I think the answers are in the note :
Core Data Release Notes for Mac OS X Lion
http://developer.apple.com/library/mac/#releasenotes/DataManagement/RN-CoreData/_index.html
For NSPrivateQueueConcurrencyType, I think you are not right.
A child context created with this concurrency type will have its own queue.
The parent/child context is not entirely related to threading.
The parent/child seems to simplify communication between contexts.
I understand that you just have to save changes in the child contexts to bring them back in the parent context (I have not tested it yet).
Usually parent/child context pattern are related to main queue/background queue pattern but it is not mandatory.
[EDIT] It seems that access to the store (Save and Load) are done via the main context (in the main queue). So it is not a good solution to perform background fetches as the query behind executeFetchRequest will always be performed in the main queue.
For NSMainQueueConcurrencyType, it is the same as NSPrivateQueueConcurrencyType, but as it is related to main queue, I understand that you perform operation with the context without necesseraly using performBlock ; if you are in the context of the main queue, in View controller delegate code for example
(viewDidLoad, etc).
midas06 wrote:
Imagine having a parent context that does all io on a background
thread that is a private queue context, and then you do all your ui
work against a child context of the main queue type.
I understood it to be the other way around: you put the parent context on the main thread using NSMainQueueConcurrencyType and the child context on the background thread using NSPrivateQueyeConcurrencyType. Am I wrong?

Using an object beyond Autorelease context

under the "Guaranteeing the Foundation Ownership Policy" in Apple developer's site article on Autorelease pool
http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html#//apple_ref/doc/uid/20000047-997594, they talk about extending an object's lifetime beyond the Autorelease pool.
Can someone give me a situation where this concept could be used?
Short answer: What the documentation is saying is that if you need to keep an object that has been autoreleased in an autorelease pool, you need to retain it.
Long answer: For instance, say I need to do a certain operation to 1000 objects. Once I'm done with these objects I'm going to autorelease them. Without an autorelease pool, they're going to be eventually released, but holding those 1000 objects in memory can make your program really slow (at least until they're autoreleased).
In order to solve this issue, I'm creating an autorelease pool that will be cleaned every 100 objects. However, what happens if I need to keep the last object of the last batch around? I still need to purge those other 99 objects. What I'm going to do is send a retain message to that very last object then clean the autorelease pool.
This way the autorelease pool will notify the system that it no longer wants those 100 items, but you've already let the system know that you do need one of them. If the object had a previous retain count of 1, then it'll still be around:
1 (original retain count) +1 (your retain) -1 (autorelease pool release) = 1.
This preserves the object after the autorelease pool is done with it.

Should an NSLock instance be "global"?

Should I make a single NSLock instance in the application delegate, to be used by all classes? Or is it advisable to have each class instantiate its own NSLock instance as needed?
Would the locking work in the second case, if I, for example, had access to a managed object context that is spread across two view controllers?
If multiple objects access your object only to read its contents, then you do not need a lock at all. If at least one of the objects accesses your object to write/update its contents, then it does not matter if the other objects access your object to read or write/update it: in this case you need a lock.
Now, in order to correctly protect your object (in a critical section of code where multiple objects may access it), you must use the SAME LOCK INSTANCE which must then be shared by ALL of the possible objects accessing the object you are willing to protect.
If your application need to protect an object that may be accessed simultaneously by the majority of the classes, then having a single lock instance is fine. If you want better performances (especially if the number of simultaneous accesses to your object is high), then you can have multiple locks. Each lock will be responsible for allowing/denying access to a specific attribute/field of your object. This way, several objects may access your object changing a different attribute/field simultaneously. You are basically incrementing the number of concurrent operations on your object. However, each lock MUST STILL be shared among the other objects that will access the object you are protecting.
Having a lock instance for each controller simply does NOT work; this will NOT protect your object from concurrent accesses from other objects in different threads. NSLock is implemented using POSIX pthread mutexes, so it must be used in exactly the same way. This is also clearly stated in the NSLock documentation:
Warning: The NSLock class uses POSIX threads to implement its locking behavior. When sending an unlock message to an NSLock object, you must be sure that message is sent from the same thread that sent the initial lock message. Unlocking a lock from a different thread can result in undefined behavior.
So, in order to preserve the critical section semantics, it is the same thread that acquired the lock that is responsible for releasing it when done. Note also that the locking mechanism is intended for fast operations only, i.e. you should acquire a lock only for a short period of time before releasing it. If you need to wait for an unpredictable amount of time, then you need a different synchronization mechanism, namely a condition variable which is available through the NSCondition class.
Hope this helps.
You should not use locks with Core Data. That documentation is probably out of date. Ideally you should have one context per thread and let the context handle the locking of its underlying NSPersistentStoreCoordinator. This is considered the only safe way to use Core Data in a multi-threaded application currently.