How to do lengthy operations without being killed by the watchdog? iphone - ios

I have an important operation that is executed rarely. In some cases, it might take minutes to execute. My app is getting killed after a 50 second operation. How to avoid that?
Should I put it in a background thread? Could anyone please point me in the right direction here. I have not found any useful information about the so called watchdog. Is a background thread the way to go?

Yes, you need to move this task to a background thread. You should never jam up the main thread with any task that takes longer than a fraction of a second to perform. Ignoring the watchdog timer, which only kicks in under extreme conditions, your application is completely unresponsive to touch or other events during this lengthy operation, and you're unable to provide feedback to the user as to the progression of this operation.
The watchdog timer will kill an application that jams up the main thread for an extremely long period of time, making the application unresponsive to input (I believe this duration is currently 20 seconds on startup, but I'm not sure what it is for when the application is running). You should never let your application get to the point where the watchdog is killing it, because that's pointing to a real problem in the way your application is handling things.
Moving a long-running task to a background thread is a lengthy topic by itself, which is why I recommend reading Apple's Concurrency Programming Guide (updated) as well as watching some of their WWDC videos on the subject before starting.
However, in my opinion the most elegant way to deal with long-running tasks is to use Grand Central Dispatch, where something like
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Do your long-running task here
dispatch_async(dispatch_get_main_queue(), ^{
// Do callbacks to any UI updates here, like for a status indicator
});
});
will fire off your task to be performed in a background thread on one of the global concurrent queues. The little section of code within the main block shows how you might update any UI elements, such as a progress bar, from within this background task. Generally, UI updates must be performed on the main thread (there are some exceptions as of iOS 4.0, but it's still a good practice in general).
I also highly recommend adding some kind of visual indication of the status of this long-running task as it proceeds. Your users will really appreciate this, and it will make your application appear faster, even though it may run for the same duration.

Can you occasionally hit the watchdog during your process? Watchdog timers are just there to detect whether something crashed. They aren't really concerned with the system being busy.
Is the phone still able to respond to the user doing stuff like pressing the home button during your process?
EDIT: This guys recommends using a background thread

Related

What happens in hardware on SAME thread async calls?

Note, related but not the same: iPhone - Grand Central Dispatch main thread
I've failed at this question many times, so here's source code:
While on the main thread
dispatch_async( dispatch_get_main_queue(), ^{ NSString * str = #"Interrupt myself to do something."} );
I'm just curious, when a thread switches, it stores its registers in Thread Local Storage, switches context, runs from its new spot in the Program Counter (which I assume is within a copy of the program that simply uses a different stack and register), then it "goes back" to the main thread.
When it interrupts itself, I'm just wondering what decides when it should, and what happens to the Thread Local stuff.
I've read up on this a little, but I'm still wrapping my head around the fact that programs are not continuous. They're just "something to do in small chunks when the OS decides to run a chunk of a process, or its chunks (threads).
I am self-taught, which might add to my lack of register/asm knowledge that may be standard to any scholar.
Thanks. The code should help, this is iOS specific, but I believe the answer/question is related to any language going from main-to-main.
Since every past attempt has resulted in lengthy answers that ignore the reason I'm asking this, I will iterate one last time....
This is for the SAME thread. Main-to-main. Does it really just stop itself, move the program counter elsewhere, go, then end at the block? Also don't these things usually change at branches (if/for and blocks too).
Pointing me in the right direction works too, but like I said, previously the question was misread.
It is hard to answer your question specifically without having access to the internals of GCD, but generically, the answer is no, simply adding a unit of work to a dispatch queue will not immediately interrupt the executing code.
As you suggest context switches are expensive, not only in terms of state saving & restoration but also the processor will need to dump the instruction pipeline resulting in wasted cycles.
Typically the operating system will keep executing the current task until it suspends (e.g. waits on a network or other IO operation) or perhaps is interrupted by some external event (pressing the home key on the phone), but there are also time limits to prevent a runaway task from locking the whole device (This is pre-emptive multi-tasking, as opposed to co-operative multitasking where the task needs to relinquish the CPU)
With dispatch_async there is no guarantee of when the code will execute in relation to the current code block. The code block may not even be next in the queue - other threads may have added other units of work to the queue before this one.
I think the thing that's confusing you is the use of dispatch_async( dispatch_get_main_queue()), which submits code to run on a queue on the main thread.
Using dispatch_async on the main queue:
When you call dispatch_async( dispatch_get_main_queue()), it adds a unit of work to the main queue, which runs it's jobs from the main thread.
If you run this call from the main thread, the results are the same. The work gets added to the main queue for later processing.
When you make this call from the main thread, the system doesn't check the main queue for work to do until your code returns.
Think of this as a one-cook kitchen. As the cook works, he puts trays of dishes in the dishwashing area. He doesn't stop to do dishes until he gets to a breaking point in what he's currently doing. At that point he takes a tray of dishes, loads it into the dishwasher, and then goes back to cooking.
The cook knows that he has to check for dishes each time he gets to a breaking point, and then completes a dishwashing task before returning to cooking.
Using dispatch_async on a background queue:
A dispatch_async call to a background queue is like a 2-person kitchen. There is a dishwasher working at the same time. The cook puts a tray of dishes into the dishwashing station (the queue) and the dishwasher (the other thread) picks up that task as soon as it's finished with it's previous tasks, while the cook continues to work on cooking.
The above assumes a machine with multiple processors, which is the norm these days. Each processor can do work at the same time without having to juggle multiple tasks.
If you are running on a single-core system with preemptive multitasking, submitting tasks to separate threads/background queues has the same effect as if there were multiple processors, but now the OS has to do a juggling act. There's only one person in the kitchen, but he wears multiple hats. The person is doing the cook job, and the OS shouts "Switch!" The cook jots down notes on what he was doing (saves state) and then jumps into the dish-pit and starts washing dishes, and keeps washing dishes until the OS yells "Switch!" again, and the worker again saves state, switches to the next role, and picks up that role (cook) where it was left off.
Multi-tasking is more costly on a single-core system because each time the worker switches roles, it has to save the current state, then load the saved state for the other role, and continue. Those context switches take time.

grand central dispatch, operation queues, async, view will and did disappear

Hopefully these questions will seem helpful to people out there. I've been learning objective c, mostly from this book, which I found to be amazing and helpful even for a noob. My questions all have to deal with this:
What happens to the queue when the user changes the view? I can't seem to find a good explanation anywhere.
From my understanding, using the NSOperation and its queue, you can always cancel it using the "cancel"...but what if you don't want it to cancel? What if, say a user selects multiple images to upload to the server, and you create a queue with the order, and the user switches to a new view controller? This might be time consuming, especially on a slow mobile network. I remember reading somewhere that iOS gives around 20 seconds extra time for a method to finish its work, but I think that's only when the app enters to the background.
For the GCD, there is no cancel method...so what happens in the background if you use async? I guess if you don't have a response to the queue, I mean you don't update the UI in any way, shouldn't the queue finish since it's sent to another thread?
I'm sure there is much more that I don't understand as far as threading goes, but I hope I made my question clear. And please please don't tell me to use the AFNetworking stuff...I tried using all those keychain wrappers out there and it all failed. Thanks to the book, the straight Apple code from the book did everything easily. I would rather learn the basics first before using the easier way out.
I would really appreciate if someone took the time to talk about this. Thanks in advance!
Your concern about only having a set amount of time to finish tasks only applies to when you switch away from your app to another app. And in that case you can use the beginBackgroundTaskWithExpirationHandler method so your app can request time to finish those tasks if your app happens to go into background. See the Executing a Finite-Length Task in the Background section of the App States and Multitasking section of the iOS App Programming Guide for more information.
But if you're still within your app (whether you transitioned to another view controller or not), anything you've added to your operation queue will continue to run until you cancel those operations (or the app is suspended or terminated). Likewise, anything you've added to a GCD queues will continue to run until the app is suspended or terminated.
In both of these scenarios, the above beginBackgroundTaskWithExpirationHandler will give you a few minutes to finish your queued tasks/operations after your app goes into the background.

Will a background thread that receives a return eventually close itself?

It looks like if a background thread is running when you hit the home button, things are suspended and then resumed when reopening the app. I simply want things to stop when the home button is pressed so that on resume, the user can start things from the beginning. After doing some research, it looks like a simple bool flag to periodically check is the way to go. My question, is the part after that. I have the flag part working using some of the notifications like UIApplicationWillResignActiveNotification, but my question is what action to take to actually stop things. I can do a simple return to stop things, but how does that affect the thread itself? As a general question, if nothing is running, or it gets to the end of the code, will the thread close itself? Or is some sort of explicit exit call needed? In my rough testing, that thread seems to go away, but I wasn't sure.
If you have a thread whose entry point returns, your thread will close. If you install a runloop, your thread may never close, depending on your implementation. In any case, when an app enters background, the main thread is allowed to complete the current runloop run and then the app is suspended. All other threads are suspended also. Once your app returns to the foreground, or when woken up in the background under certain circumstances, your thread will resume work until you end the entry point, suspend it or your app is suspended again.
This is a simplification, of course. In some instances, threads are reused, even if your provided entry point returns. This is the case of thread pools, GCD, etc. In these cases, a thread may appear as alive, but it is actually suspended and takes little resources.

Understanding Multithreading in iOS

I am trying to understand multi-threading on iOS in more detail. I went through some of the class references like NSThread, NSRunLoop, NSTask..
First of all as indicated on the following link:
use of runloop
Runloop runs within a Thread.
So why do we need to define our own Runloop in our app? In the case of NSThread it is useful because some of time-consuming processes can run in a separate thread so that the app will still be responsive on the main thread.
Interacting with the thread's run loop may be useful if you have a thread whose work you want to continue periodically. That is, a run loop would do some work, and then when it is finished with that work, it would put the thread to rest for some time, then resume work at a later time -- effectively preventing the thread from exiting. You won't need to interact with them or configure/create them yourself regularly (only a small percentage of apps would qualify, if you are using high level abstractions such as Foundation because Foundation would set them up on your behalf in most scenarios).
If your secondary thread just does a specified task and does not need to wait for some external event (e.g. a download to finish), you would (typically) not need to interact with the run loop.
You might consider looking at using NSOperationQueues, NSOperations and NSBlockOperations instead as these will manage themselves, will allow for cancellation of tasks and can be scheduled on main and background threads.

Are all methods in an iOS app usually in a single thread? (for race condition prevention)

We can have many handlers: touches handler, UIControl handler (buttons, sliders), performSelector, CADisplayLink, NSTimer events, Gesture Recognizer, accelerometer handler, and UIView animation completion block, and some other ones.
Are all of them in the same thread? That is, only one of them can be running at the same time?
Can some other method or handler be part of another thread and therefore can create race conditions?
In general, you'll find that most simple applications on iOS tend to perform almost every action on the main thread. As you noted, the instant that you bring multithreading into the picture you add another set of tricky issues to watch out for. Many developers don't want to bother with this added complexity, or are unfamiliar with GCD or threading in general, so they avoid doing anything on a background thread or GCD queue.
Several of the items you list in your question involve interactions with UIKit, and in general those interactions must occur on the main thread (iOS 4.x added the ability to perform some drawing functions in the background, though). You receive touch and other related events on the main thread. If you wish to update most aspects of an interface, the safe way to do that is by performing these updates on the main thread.
Timers (NSTimer, CADisplayLink) can have their updates be fired on a background thread by attaching them to an NSRunLoop operating on that background thread. You rarely see people do this, but it can be done. Usually, people configure timers on the main run loop, which causes callbacks to be delivered on the main thread.
When performing animations, the animations themselves will run on a background thread (you see that they don't stop while you're blocking the main thread with something else), but you'll almost always receive a completion block or callback on the main thread when they're done. If I remember correctly, there are one or two exceptions to this and they are noted as such in Apple's documentation. Having these callbacks trigger on the main thread is a safe approach when dealing with developers who might not realize what's going on behind the scenes.
All that said, there are very good reasons to want to add multithreading to your application. Because all user interface updates and touch interactions occur on the main thread, if you have something that is computationally expensive or that simply will take a lot of time to perform, if you run this on your main thread you'll appear to have frozen your application. This is a terrible user experience, so you want to move this task onto a background thread so that the user can keep interacting with your application while this is going on. Additionally, more and more iOS devices are shipping every day with multiple cores in them, and balancing your work load across these cores and being efficient with this hardware requires some degree of concurrent processing.
People have written books about best practices when making code multithreaded, and you can find a lot of questions about this here, so I won't go into too much detail. What I can tell you is that you should read Apple's Concurrency Programming Guide and watch the WWDC videos from the last two years that deal with Grand Central Dispatch. With GCD, Apple has made it a lot easier to add multithreading to your application in an efficient and (relatively) safe manner, and I encourage you to look into this for your own applications.
For example, I have an open source iOS application that performs detailed rendering of molecular structures. I render each frame on a background GCD queue because sometimes they take more than 1/60th of a second to process, and in those cases they'd cause touch events to be dropped and the interface to stutter if this was all on the main thread. Additionally, I've seen up to a 40% performance boost by doing this when running on the newer multicore devices. To avoid race conditions, I wrap interactions with shared data structures and contexts in serial dispatch queues so that only one action can be using a resource at a time, no matter what thread a particular block is running on. This only required the addition of a few lines of code, but the performance and user experience benefits were huge.

Resources