For performance reasons, I instantiate a dedicated NSThread to process incoming messages that are streamed from a network server. I use an NSOperation for the purpose of instantiating the connection and receiving incoming data through the NSURLConnection delegates, but as soon as new data comes in and gets parsed, I offload the processing of the message to the dedicated NSThread. The idea is to let one thread focus on receiving incoming messages and let the other thread just do the processing.
What's the proper way to shut down the NSThread when the applicationDidEnterBackground comes in?
Also, how should I restart the NSThread when applicationWillEnterForeground comes in?
Other than the main thread, it seems the state of other background threads is not maintained between going to sleep and restarting.
By the way, I'm all for using NSOperations for most tasks that have a measurable amount of work -- ie, accessing a resource over the network, performing a calculation, etc. However, in this case, I need to process messages on the fly on a long-living dedicated thread that is always there by calling performSelector:onThread:withObject:waitUntilDone: and passing it the target thread. It seems NSOperation isn't a good fit for this.
I would appreciate your input.
"For performance reasons"?
If processing doesn't take much time, run everything (including NSURLConnection) on the main thread. Concurrency bugs are a major pain.
If you want things to run serially, you can emulate a "single thread" with an NSOperationQueue with maxConcurrentOperations = 1. I'm pretty sure that NSOperationQueue uses thread pools (and on 4.0, GCD, which probably uses thread pools), which means you don't need to keep a thread running all the time.
Apart from that, your process is automatically suspended and resumed by the system, so you don't need to kill off threads.
I'm not sure what you mean by "the state of other background threads".
Related
I have a high-priority audio thread that runs periodically and should do minimal synchronization.
Sometimes the main thread needs to ensure that at least one audio cycle has passed and certain parameters have been picked up, before sending the next batch of parameters. For example, when disabling an audio node the main thread needs to wait until the next cycle when the disabling command is picked up and the node shuts itself down.
At times it is important for the main thread to wait until the command is fully executed, but other times it's not important, so nobody might be listening to the sync event. Hence the "lossy" scenario.
So what is the best way of notifying other threads about an event with minimal overhead and possibly in a "lossy" way?
Can't think of ways of using a semaphore for this task. Are there any canonical ways of achieving this? Looks like Java's notifyAll() works precisely this way, if so, what synchronization mechanism is used behind notifyAll()?
Edit: been thinking, is there such a thing as "send me a semaphore in a queue and I'll signal it"? Seems a bit too complicated but theoretically it could do the job. Any simpler tools for the same task?
As a rule, you never want to block the main thread (or, at least, for more than a few milliseconds). If the response might ever take longer than that, rather than actually waiting, we would adopt asynchronous patterns, let the main thread proceed. Sure, if you need to prevent user interaction, we’d do that, but we wouldn't block the main thread.
The key concern is that if an app blocks the main thread for too long, you have a bad UX (where the app appears to freeze) and you risk having your app killed by the watchdog process. I would therefore not advise using semaphores (or any other similar mechanisms) to have the main thread wait for something from your audio engine controller.
So, for example, let’s say the main thread wants to tell the audio engine to pause playback, but you want the UI to “wait” for it to be acknowledged and handled. Instead of actually waiting, we would set up some asynchronous pattern where the main thread notifies the audio engine that it wants it to pause, the audio controller would then notify the main thread when that request has been processed via some callback mechanism (e.g., via delegate protocol pattern, completion handler closure, etc.). If you happen to need to prevent user interaction during the intervening time, then you’d disable controller and use some UIActivityIndicatorView (i.e., a spinner) or something like that, something that would be removed when the completion handler is called.
Now, you used the term “lossy”, but that generally conveys that you don't mind the request getting lost. But I’m assuming that is not really the case. I'm assuming that you don't really want the request to be lost, but rather only that the main thread doesn't care about the response, confident that the audio controller will get to it when it can. In that case, you'd probably still give this sort of request to the audio controller a callback mechanism, but the main thread just wouldn’t avail itself of it.
Now if you have a sequence of commands that you want the audio engine to process in order, then the audio controller might have a private, internal queue for these requests, where you’d configure it to not start subsequent request(s) until the prior ones finished. The main thread shouldn't be worried about whether the required audio cycle has processed. It should just send whatever requests are appropriate and the audio controller should handle them in the desired order/timing.
According to the documentation of CLLocationManagerDelegate
The methods of your delegate object are called from the thread in which you started the corresponding location services. That thread must itself have an active run loop, like the one found in your application’s main thread.
I am not clear as to whether this means that to receive location manager updates on a background thread, we must instantiate the location manager on that background thread or simply call the startUpdatingLocation() method on that thread.
In any event, this explains an issue when a CLLocationManagerDelegate does not receive any events from a CLLocationManager which was started on a background thread:
That thread must itself have an active run loop
If I understand run loop functioning correctly, all NSThreads are instantiated with a run loop, but the run loop will only be running if you assign some work to the thread. Therefore, to have a CLLocationManager send events correctly on a background thread, we need to set the thread's run loop to loop permanently so that it can process the CLLocationManager's calls as they arrive.
A reasonable solution to making sure the run loop is running is suggested in this question but the author implies that this is a processor expensive way of doing it.
Also, according to the threading documentation,
Threading has a real cost to your program (and the system) in terms of memory use and performance
I appreciate that we are all using lots of threading anyway, by using Grand Central Dispatch, but Grand Central Dispatch probably mitigates a lot of this in its internal thread management.
So my first question is, is it worthwhile setting up a background thread with a continuously running run loop, in order to have location events dealt with on a background thread, or will this involve an unreasonable extra amount of processing when compared to leaving the manager on the main thread?
Secondly, if it is worthwhile, is there a good way to do this using Grand Central Dispatch. As I understand the documentation, Grand Central Dispatch manages its own threads and we have no means of knowing which thread a given block will be executed on. I presume we could simply execute the usual run loop code to make the run loop of whichever thread our CLLocationManager instantiation is run on loop continuously, but might this not then affect other tasks independently assigned to Grand Central Dispatch?
This is a somewhat opinion-based question, but I have a pretty strong opinion on it :D
No.
Just deliver the events to the main queue, and dispatch any work to a background queue if it's non-trivial. Anything else is a lot of complexity for little benefit. CLLocationManager pre-dates GCD, so this was useful information in the days when we occasionally managed run loops by hand and dispatching from one thread to another was a pain. GCD gets rid of most of that, and is absolutely the tool you should use for this. Just let GCD handle it with dispatch_async.
You absolutely should not set up your own NSThread for this kind of thing. They're still necessary at times for interacting with C++, but generally if GCD can handle something, you should let it, and avoid NSThread as much as possible.
I have a background thread that is doing a bunch of work - loading the application. The main thread is displaying progress on a UIProgressView.
The background thread is being spawned with performSelectorInBackground (though, I'm not wed to this method if a different approach makes this problem easier to solve)
[self performSelectorInBackground:#selector(loadAppInBackground) withObject:self];
On a couple occasions a bug has caused the background thread to crash (different bugs as the app evolves) which results in the progress bar stopping, but the user getting no clear indication that anything is wrong.
I'd like to detect this situation and fail more gracefully than simply hanging until the user gives up on waiting.
Because the duration of the load process can vary greatly, simply timing out isn't an ideal option.
What's the best way for the foreground thread to detect that the background thread has failed? Since the foreground thread is busy dealing with the UI, would it require a second background thread to monitor the first? That seems ugly.
Is there some thread-to-thread communication mechanism that could be used to "ping" the background process? Better yet, a low level system mechanism of checking the status of other threads?
The debugger knows about all the threads that are running... and seems to know their status. I'm wondering if there's a call available to my app to do the same.
If the background task runs in some sort of regular cycle (eg, there's a big loop where much of the work gets done), it can set a flag every so often to indicate that it's still alive.
One way to do this is to have background thread store [NSDate timeIntervalSinceReferenceDate] somewhere, and, in your main thread, occasionally (perhaps on a timer) compare that to the current time. If the difference is greater than some reasonable limit you can guess that the background thread has died.
Another way is to have the background thread simply set a Boolean, and have the main thread interrogate that and clear it on some regular basis. If the Boolean doesn't get set again between main thread interrogations you can infer that it has died.
The first technique has the advantage that you can "tune" the "reasonable limit" to tolerate code (in either thread) that is somewhat irregular in it's timing. The second approach generally requires timings that are more predictable.
Of course with either approach you want to somehow avoid "blowing the whistle" if the background thread has just finished up and you simply haven't recognized that yet.
A common technique is to have an extra thread to check for life signs of the thread in question - a so called heartbeat thread. The heartbeat thread polls the thread by checking if it responds in a timely manner, if not, deems the thread dead and terminates it.
A simple heartbeat thread implementation would be to check a counter that is incremented regularly by the other thread, if the counter is not incremented within a certain time it is regarded as dead and then an appropriate action could be taken like restarting thread or killing app. Another more common way is if the hb thread sends messages to the thread and checks for a response with a timeout.
It seems like there is no mechanism in objective c to check the status of a background thread directly. Any of the answers provided are decent options... either timing out, or having the thread create some sort of evidence of its continued existence.
I was hoping for something a little more simple, reliable, and real-time.
I'm going to experiment with catching an exception in the thread and perhaps producing a notification like "BackgroundThreadException" that the foreground thread could listen for and react to.
In my app created NSOperationQueue of NSOperation to download multiple images in background.I wanted to know what will happen if network connection is lost while downloading data.Whether all those are operations which are still in queue are marked as finished and removed from queue or will remain in queue and again start downloading process when network is established again or something else?
Can anyone explain how NSOperationQueue works in such scenario?
Thanks in advance!
The current NSOperation will continue with whatever logic is left when it receives the failure signal, and then terminate as normal, causing the NSOperationQueue to begin running the next NSOperation. If the internet still isn't back, it'll fail as well, and will just keep moving through the queue whether the network re-connects or not, failing all the connections unless the network reconnects.
There's probably quite a few different ways to handle this, because there's a lot to consider. For instance, you could put some logic in your code to mark an NSOperation as unsuccessful if it fails due to a network drop-out, and re-add failed NSOperations back into the queue. However, what if the network stays down for ages? Would your implementation be okay to keep trying to download images forever, or should you only let it re-try a particular file download a few times before giving up until the next time that feature is used?
You could also use a series of network reachability checks, such as before an NSOperation is added to the queue, before the NSOperation itself launches the NSURLConnection, etc. Should it fail you could have the NSOperation wait around until the network is re-connected and continue. (It's not ideal to do that, but because you're running it on a background thread it won't freeze the app's interface for the user at least).
If you wanted to, you could even implement the functionality you asked about in your question. That is, upon a network drop-out, cancelling all remaining operations in the NSOperationQueue, informing the user they'll have to re-try when the net comes back on. Then the next time the feature is called, re-add all those remaining NSOperations.
Is there any way I can kill a thread spawn through:
[NSThread detachNewThreadSelector:#selector(serverFetchInThread) toTarget:self withObject:nil];
The scenario I am working on is that in my main thread I am letting user enter data in my search bar and what ever user is typing I need to send to server for searching in a separate thread. Now, if user changes his selection by deleting old data and entering new data I do not want the previous thread to waste its time, kill it and spawn a new thread with new data.
Be there any other better way to handle this situation, please guide me.
No, there is no way to kill a thread from another thread. And for good reason as there is no way to do so in a fashion where the targeted thread is killed without risk of crashing the app.
To directly answer your question; you need to have some kind of a flag that indicates to the thread that it should stop doing whatever it is doing and exit.
However, a couple of questions are raised by your question:
First, why are you using threads and not using GCD? Concurrency via GCD or NSOperation is the generally recommended way to solve such problems.
Secondly, if you are talking to a server, are you using HTTP (most of the time, that is the case)? If so, why not directly use the asynchronous features of NSURL and friends?
Have a good look at using NSOperationQueue.
You can subclass NSOperation it to wrap up your server communications, and even make that queue serial (maximum operations = 1).
If a server operation is not yet finished and user has generated more input, you can cancel the existing one, and add the new one.
Due to the effect of the NSOperation wrapping your connection, you can just use the simple synchronous version and keep the connection handling very straightforward.
Also worth mentioning is compatibility. I would prefer to use GCD and blocks, but for compatibility, NSOperationQueue is required.